home *** CD-ROM | disk | FTP | other *** search
/ Developer CD Series 2000 April: Mac OS SDK / Dev.CD Apr 00 SDK1.toast / Development Kits / Mac OS / Navigation Services SDK / Examples / SimpleText / SimpleText ƒ / GXFile.c < prev    next >
Encoding:
C/C++ Source or Header  |  1999-06-16  |  95.1 KB  |  3,208 lines  |  [TEXT/MPS ]

  1. /*
  2.     File:        GXFile.c
  3.  
  4.     Copyright:    © 1997-1998 by Apple Computer, Inc., all rights reserved.
  5.  
  6. */
  7.  
  8. /*
  9. **    You may incorporate this sample code into your applications without
  10. **    restriction, though the sample code has been provided "AS IS" and the
  11. **    responsibility for its operation is 100% yours.  However, what you are
  12. **    not permitted to do is to redistribute the source as "DSC Sample Code"
  13. **    after having made changes. If you're going to re-distribute the source,
  14. **    we require that you make it clear in the source that the code was
  15. **    descended from Apple Sample Code, but that you've made changes.
  16. */
  17.  
  18. #include "MacIncludes.h"
  19.  
  20. #include "GXFile.h"
  21.  
  22.  
  23. #include "NavigationServicesSupport.h"
  24.  
  25.  
  26. #pragma segment GXFile
  27.  
  28.  
  29.  
  30. // --------------------------------------------------------------------------------------------------------------
  31. // PRIVATE TYPEDEFS AND DECLARES
  32. // --------------------------------------------------------------------------------------------------------------
  33. // items to the left of the horizontal scroll bar
  34. #define kScrollAreaWidth    120
  35. #define kPageControlsWidth    32
  36. #define kZoomControlsWidth    26
  37. #define kToolControlWidth    16
  38.  
  39. // items in the pop up page selection window
  40. #define kPageSliderHeight    10
  41. #define kPageSliderMargins    7
  42. #define kPageThumbEdge        4
  43. #define kPageThumbHeight    (kPageSliderHeight + kPageThumbEdge*2)
  44. #define kPageThumbWidth        (kPageThumbHeight / 2)
  45. #define kPageThumbMargins    3
  46. #define kProxyHeight        150
  47. #define kProxyWidth            150
  48. #define kPopUpWindowHeightSmall    (kPageThumbHeight + kPageSliderMargins*2 + kPageThumbEdge*2)
  49. #define kPopUpWindowHeightLarge    (kPageThumbHeight + kPageSliderMargins*3 + kPageThumbEdge*2 + kProxyHeight)
  50.  
  51. #define kMinGXDocSize        kMinDocSize
  52.  
  53. // PICT proxies for the pages
  54. #define kProxyBaseID        (gxPrintingTagID)
  55. #define kProxyType            'prxy'
  56.  
  57. // flattened GX shapes for annotations
  58. #define kAnnotationBaseID    (gxPrintingTagID)
  59. #define kAnnotationType        'anot'
  60.  
  61. // table of pop up menu items and corosponding zoom factors
  62. typedef struct
  63.     {
  64.     short    menuItem;
  65.     Fixed    zoomFactor;
  66.     } ZoomTableEntry;
  67.     
  68. typedef struct
  69.     {
  70.     short    theFont;
  71.     short    theSize;
  72.     } TextState;
  73.     
  74. typedef struct  
  75.     {
  76.     gxSpoolBlock    spool;
  77.     long            reference;
  78.     long            position;
  79.     long            size;
  80.     void            *data;
  81.     void            *userField;
  82.     } userSpool;
  83.  
  84. #define LONGALIGN(n)        (((n) + 3) & ~3L)
  85. #define kAtomHeaderSize        (sizeof(Size) + sizeof(OSType))
  86. #define ABS(n)                (((n) < 0) ? -(n) : (n))
  87.  
  88. #if GENERATINGCFM
  89.     extern pascal OSErr SetImageDescriptionExtension(ImageDescriptionHandle desc, Handle extension, long idType);
  90. #endif
  91.  
  92.  
  93.  
  94. // --------------------------------------------------------------------------------------------------------------
  95. // FORWARD DECLARES
  96. // --------------------------------------------------------------------------------------------------------------
  97. OSErr    GXGetDocumentRect(WindowRef pWindow, WindowDataPtr pData, 
  98.             LongRect * documentRectangle, Boolean forGrow);
  99. OSErr    GXCommand(WindowRef pWindow, WindowDataPtr pData, short commandID, long menuResult);
  100.  
  101. // --------------------------------------------------------------------------------------------------------------
  102. // LOCAL GLOBALS
  103. // --------------------------------------------------------------------------------------------------------------
  104. static ZoomTableEntry gZoomTable[] = {
  105.                                 {i50,     0x8000},
  106.                                 {i100,    ff(1)},
  107.                                 {i112,    0x00011EB8},
  108.                                 {i150,     0x00018000},
  109.                                 {i200,    ff(2)},
  110.                                 {i400,    ff(4)},
  111.                                 {0,0}};
  112.  
  113.  
  114. // --------------------------------------------------------------------------------------------------------------
  115. // PRIVATE ROUTINES
  116. // --------------------------------------------------------------------------------------------------------------
  117.  
  118. static void GetCurrentPageAndPaper(WindowDataPtr pData, gxRectangle *pPageSize, gxRectangle *pPaperSize)
  119. {
  120.     GXGetFormatDimensions( ((GXDataPtr)pData)->currentPageFormat, pPageSize, pPaperSize);    
  121.     if (((GXDataPtr)pData)->dontShowMargins)
  122.         *pPaperSize = *pPageSize;
  123.         
  124. } // GetCurrentPageAndPaper
  125.  
  126. // ------------------------------------------------------------------------------------------------------
  127. static void InitColorMatrix(Fixed m[5][4])
  128. {
  129.     register Fixed *x;
  130.     register short i;
  131.  
  132.     x = &m[0][0];
  133.     for(i = 19; i>=0; i--)
  134.         *x++ = 0;
  135.     m[0][0] = m[1][1] = m[2][2] = m[3][3] = fixed1;           /* Identity matrix, for cleanliness */
  136.     
  137. } // InitColorMatrix
  138.  
  139. // --------------------------------------------------------------------------------------------------------------
  140. static void RectangleToRect(const gxRectangle* gxr, Rect* qdr)
  141. {
  142.     qdr->left = FixedRound(gxr->left);
  143.     qdr->top = FixedRound(gxr->top);
  144.     qdr->right = FixedRound(gxr->right);
  145.     qdr->bottom = FixedRound(gxr->bottom);
  146.     
  147. } // RectangleToRect
  148.  
  149. // --------------------------------------------------------------------------------------------------------------
  150. #define allocationIncrement   1024     /* the storage handle is grown by this amount */
  151.  
  152. static long HandleSpoolProc(gxSpoolCommand command,  userSpool *block)
  153. {
  154.     gxGraphicsError    anErr = noErr;
  155.     
  156.        switch (command)
  157.            {
  158.           case gxOpenReadSpool:
  159.              block->size = 0;
  160.              block->position = 0;
  161.               break;
  162.       
  163.           case gxOpenWriteSpool:
  164.              block->data = NewHandle(allocationIncrement);
  165.              block->size = allocationIncrement;
  166.              block->position = 0;
  167.             anErr = MemError();
  168.               break;
  169.       
  170.           case gxReadSpool:
  171.              BlockMoveData((*(char **) block->data) + block->position, block->spool.buffer, block->spool.count);
  172.              block->position += block->spool.count;
  173.               break;
  174.  
  175.           case gxWriteSpool:
  176.               {  
  177.             register long oldPosition;
  178.  
  179.             oldPosition = block->position;
  180.             block->position += block->spool.count;
  181.  
  182.             /* make sure there is at least enough room for one buffer size past current pointer */
  183.             if (block->position + block->spool.bufferSize > block->size)      
  184.                  {
  185.                 block->size += block->spool.bufferSize;
  186.                 HUnlock((Handle) block->data);
  187.                 SetHandleSize((Handle) block->data, block->size);
  188.                 anErr = MemError();
  189.                 HLock((Handle) block->data);
  190.                  }
  191.             if (anErr == noErr)
  192.                  BlockMoveData(block->spool.buffer, (*(char **) block->data + oldPosition), block->spool.count);
  193.               }
  194.               break;
  195.       
  196.           case gxCloseSpool:
  197.              SetHandleSize((Handle) block->data, block->position);
  198.               break;
  199.            }
  200.         
  201.    return anErr;
  202.    
  203. } // HandleSpoolProc
  204.  
  205. #if GENERATINGCFM
  206.     static RoutineDescriptor gHandleSpoolProcRD = BUILD_ROUTINE_DESCRIPTOR(uppgxSpoolProcInfo, HandleSpoolProc);
  207.     static gxSpoolUPP gHandleSpoolProc = &gHandleSpoolProcRD;
  208. #else
  209.     static gxSpoolUPP gHandleSpoolProc = NewgxSpoolProc(HandleSpoolProc);
  210. #endif
  211.  
  212. // --------------------------------------------------------------------------------------------------------------
  213. static long* AppendAtom(long stream[], Size size, OSType tag, const void* data)
  214. {
  215.  
  216.     *stream++    = size + kAtomHeaderSize;
  217.     *stream++    = tag;
  218.     BlockMoveData(data, (Ptr)stream, size);
  219.  
  220.     return (long*)((char*)stream + size);
  221.     
  222. } // AppendAtom
  223.  
  224. // --------------------------------------------------------------------------------------------------------------
  225. static Handle CreateQDGXStream(gxShape source, PicHandle proxie, Boolean forPrintingOnly, Boolean eraseBackground)
  226. /*
  227.  *    See the comment on DecompressShape for an explaination of the parameters.
  228.  *    This routine is used by both DecompressShape for embedding shapes in PICTs,
  229.  *    and AddQDGXRecorderFrame for making gx movies.
  230. */
  231. {
  232.     #define            gxForPrintingOnlyAtom    'fpto'
  233.     #define            gxEraseBackgroundAtom    'erbg'
  234.  
  235.     long            atomCount, shapeSize, proxieSize, dataSize, fontListSize;
  236.     Handle            dataHdl, shapeHdl;
  237.     gxFlatFontList*    fontList;
  238.     gxTag            fontListTag;
  239.       userSpool         block;
  240.  
  241.     block.spool.spoolProcedure = gHandleSpoolProc;
  242.     block.spool.buffer = nil;
  243.     block.spool.bufferSize = 0;
  244.     GXFlattenShape(source, gxFontListFlatten | gxFontGlyphsFlatten | gxFontVariationsFlatten, &block.spool);
  245.     shapeHdl = (Handle) block.data;
  246.     if (shapeHdl == nil)
  247.         return nil;
  248.  
  249.     if (proxie)
  250.         {    
  251.         atomCount = 2;
  252.         proxieSize = LONGALIGN(GetHandleSize((Handle)proxie));
  253.         }
  254.     else
  255.         {    
  256.         atomCount = 1;
  257.         proxieSize = 0;
  258.         }
  259.     shapeSize = LONGALIGN(GetHandleSize(shapeHdl));
  260.  
  261.     if (forPrintingOnly)
  262.         ++atomCount;
  263.     if (eraseBackground)
  264.         ++atomCount;
  265.  
  266.     fontListSize = 0;
  267.     fontList = nil;
  268.     GXIgnoreGraphicsWarning(count_out_of_range);
  269.     if (GXGetShapeTags(source, gxFlatFontListItemTag, 1, 1, &fontListTag) > 0)
  270.         {    
  271.         fontListSize = GXGetTag(fontListTag, nil, nil);
  272.         if (fontListSize > 0)
  273.             {    
  274.             fontList = (gxFlatFontList*)NewPtr(fontListSize);
  275.             if (fontList != nil)
  276.                 {    
  277.                 GXGetTag(fontListTag, nil, fontList);
  278.                 fontListSize = LONGALIGN(fontListSize);
  279.                 ++atomCount;
  280.                 }
  281.             else
  282.                 fontListSize = 0;
  283.             }
  284.         }
  285.     GXPopGraphicsWarning();        // count_out_of_range
  286.  
  287.     dataSize = atomCount * kAtomHeaderSize + shapeSize + proxieSize + fontListSize + sizeof(long);
  288.     dataHdl = NewHandle(dataSize);
  289.     if (dataHdl == nil)
  290.         {    
  291.         DisposeHandle(shapeHdl);
  292.         if (fontList)
  293.             DisposePtr((Ptr)fontList);
  294.         return nil;
  295.         }
  296.     
  297.     {    
  298.         long* p = (long*)*dataHdl;
  299.  
  300.         if (forPrintingOnly)
  301.             p = AppendAtom(p, 0, gxForPrintingOnlyAtom, nil);
  302.         if (eraseBackground)
  303.             p = AppendAtom(p, 0, gxEraseBackgroundAtom, nil);
  304.         if (proxie)
  305.             p = AppendAtom(p, proxieSize, 'PICT', *proxie);
  306.         if (fontList)
  307.             p = AppendAtom(p, fontListSize, gxFlatFontListItemTag, fontList);
  308.         p = AppendAtom(p, shapeSize, 'qdgx', *shapeHdl);
  309.         *p++ = 0;        // end of the atom-list
  310.  
  311.         DisposeHandle(shapeHdl);
  312.         if (fontList)
  313.             DisposePtr((Ptr)fontList);
  314.     }
  315.     return dataHdl;
  316.  
  317. } // CreateQDGXStream
  318.  
  319. // --------------------------------------------------------------------------------------------------------------
  320. static PicHandle DecompressShape(gxShape theShape, PicHandle proxie, Boolean forPrintingOnly, Boolean eraseBackground)
  321. /*
  322.  *    This guy returns a Quickdraw picture containing an embedded shape, and a proxie
  323.  *    of the shape, if proxie is not nil. This is called by ShapeToScrap and DragAndDropShape.
  324.  *
  325.  *    theShape            • the shape you want to embedd in a PICT
  326.  *    proxie            • a PICT to be drawn if theShape cannot be drawn (optional but recommended)
  327.  *    forPrintingOnly        • if TRUE, then the decompressor will always look for the proxie
  328.  *                    and theShape will only be used when printing. Use this setting if
  329.  *                    theShape might be too large or too slow when drawn from other apps.
  330.  *                    • If FALSE, then the decompressor will draw theShape unless it
  331.  *                    gets an error, in which case it will look for a proxie.
  332.  *    eraseBackground    • if TRUE, the decompressor will always erase the background to WHITE
  333.  *                    before drawing the shape. This is slower, but needed if the shape does not
  334.  *                    fill its bounding rectangle.
  335.  *                    • if FALSE, the decompressor will just draw the shape. Use this setting
  336.  *                    if the shape entirely fills its bounding rectangle.
  337.  *
  338.  *    The shape [and proxie] is embedded by constructing a stream of atoms. Each atom begins
  339.  *    with a size (long) and a type (OSType) and then the data for that type. After the last atom,
  340.  *    there is a trailing zero (long) to mark the end of the stream. For embedded shapes, the type
  341.  *    is 'qdgx', and for the proxie the type is 'PICT'. Note that the size fields are rounded up to
  342.  *    a multiple of 4. Finally, to alert QuickTime that the data is in this parsable form with a
  343.  *    possible PICT proxie, we add a 'prxy' extension to the ImageDescriptionHandle.
  344.  *
  345.  *    Picture of this form will draw the embedded shape when an application calls DrawPicture
  346.  *    if GX is around, and if not, the proxie will be drawn. When printed, the shape or the proxie
  347.  *    will be printed. This is meant to replace the PicComment described in GX 1.0 for embedding
  348.  *    shapes in pictures.
  349.  *
  350.  *    If you want to include a flatFontList tag, be sure that theShape is a picture, otherwise GX will
  351.  *    not return the tag after GXFlattenShape. The flatFontList tag makes certain printing conditions
  352.  *    more efficient (i.e. font downloading to postscript printers).
  353.  *
  354.  *    Your shape must not contain a gxQuickDrawPictTag, meaning it contains embedded QD data, becuase
  355.  *    this will potentially crash when it tries to print. To fix that, DecompressShape looks for occurrances
  356.  *    of the tag, and converts them to real gx data by calling GXSetShapeType(shape, gxPictureType).
  357. */
  358. {
  359.     PicHandle                thePicture;
  360.     ImageDescriptionHandle    descHdl;
  361.     ImageDescriptionPtr        descPtr;
  362.     Handle                    dataHdl;
  363.  
  364.     if (!gMachineInfo.haveQuickTime)
  365.         return nil;
  366.  
  367.     /*
  368.      *    Move the shape's topLeft to 0,0 so that it draws neatly inside the picture frame.
  369.      *    Note that the qdgx movie library does not move the shape, since the shape may not
  370.      *    take up the whole frame.
  371.     */
  372.     {    
  373.         gxRectangle    bounds;
  374.  
  375.         GXGetShapeLocalBounds(theShape, &bounds);
  376.         if (bounds.left || bounds.top)
  377.             GXMoveShape(theShape, -bounds.left, -bounds.top);
  378.         dataHdl = CreateQDGXStream(theShape, proxie, forPrintingOnly, eraseBackground);
  379.         if (bounds.left || bounds.top)
  380.             GXMoveShape(theShape, bounds.left, bounds.top);
  381.     }
  382.     if (dataHdl == nil)
  383.         return nil;
  384.  
  385.     descHdl = (ImageDescriptionHandle)NewHandleClear(sizeof(ImageDescription));
  386.     if (descHdl)
  387.         {    
  388.         Rect            shortBounds;
  389.         gxRectangle    bounds;
  390.  
  391.         GXGetShapeLocalBounds(theShape, &bounds);
  392.         RectangleToRect(&bounds, &shortBounds);
  393.         OffsetRect(&shortBounds, -shortBounds.left, -shortBounds.top);    // set the topLeft of the src to 0,0
  394.         thePicture = OpenPicture(&shortBounds);
  395.  
  396.         descPtr = *descHdl;
  397.         descPtr->idSize = sizeof(ImageDescription);
  398.         descPtr->cType = 'qdgx';
  399.         descPtr->vendor = 'appl';
  400.         descPtr->temporalQuality = codecLosslessQuality;
  401.         descPtr->width = shortBounds.right;
  402.         descPtr->height = shortBounds.bottom;
  403.         descPtr->hRes = descPtr->vRes = ff(72);
  404.         descPtr->dataSize = GetHandleSize(dataHdl);
  405.         descPtr->frameCount = 1;
  406.         descPtr->depth = 32;
  407.         descPtr->clutID = -1;
  408.  
  409.         //    If there is a PICT proxie, add an image extension to tell QuickTime, in case GX is not around.
  410.         if (proxie)
  411.             {    
  412.             Handle prxyVersionHdl = NewHandle(sizeof(long));
  413.  
  414.             if (prxyVersionHdl != nil)
  415.                 {    
  416.                 *(long*)*prxyVersionHdl = 0;        // version number for 'prxy' extension
  417.                 #if GENERATINGCFM
  418.                     SetImageDescriptionExtension(descHdl, prxyVersionHdl, 'prxy');
  419.                 #else
  420.                     AddImageDescriptionExtension(descHdl, prxyVersionHdl, 'prxy');
  421.                 #endif
  422.                 }
  423.             }
  424.  
  425.         HLock(dataHdl);
  426.         DecompressImage(*dataHdl, descHdl, ((CGrafPtr)qd.thePort)->portPixMap, &shortBounds, &shortBounds, srcCopy, nil);
  427.         DisposeHandle((Handle)descHdl);
  428.         ClosePicture();
  429.         }
  430.     else
  431.         thePicture = nil;
  432.  
  433.     DisposeHandle(dataHdl);
  434.  
  435.     return thePicture;
  436.     
  437. } // DecompressShape
  438.  
  439. // --------------------------------------------------------------------------------------------------------------
  440. static PicHandle ShapeToPICT(gxShape source)
  441. /*
  442.  *    This guy returns a Quickdraw picture containing a 1-bit bitmap of the shape.
  443.  *    This is used by ShapeToScrap to create a proxie when calling DecompressShape.
  444.  *    If you want to make the proxie prettier (and larger), change the bitmap to 8-bit.
  445.  *    However, if you're using this in conjunction with DecompressShape to place a
  446.  *    gxShape on the clipboard, 1-bit should be enough, since the actual shape will be
  447.  *    drawn, rather than the proxie (unless forPrintingOnly is true).
  448. */
  449. {
  450.     gxRectangle        bounds;
  451.     gxShape            bitShape;
  452.     gxBitmap        bitmap;
  453.     PicHandle        thePicture;
  454.     Rect            shortBounds;
  455.  
  456.     /*
  457.      *    GetShapeLocalBounds doesn't accurately report the bounds of a gxQuickDrawPictTag.
  458.      *    but we should have none of them at this point anyway.
  459.     */
  460.     GXGetShapeLocalBounds(source, &bounds);
  461.     RectangleToRect(&bounds, &shortBounds);
  462.     OffsetRect(&shortBounds, -shortBounds.left, -shortBounds.top);
  463.  
  464.     bitmap.width        = shortBounds.right;
  465.     bitmap.height        = shortBounds.bottom;
  466.     bitmap.rowBytes        = bitmap.width + 31 >> 5 << 2;
  467.     bitmap.pixelSize    = 1;
  468.     bitmap.space        = gxIndexedSpace;
  469.     bitmap.set            = nil;
  470.     bitmap.profile        = nil;
  471.     bitmap.image        = NewPtrClear(bitmap.rowBytes * bitmap.height);
  472.     if (bitmap.image == nil)
  473.         return nil;
  474.  
  475.     bitShape = GXNewBitmap(&bitmap, nil);
  476.     if (bitShape != nil)
  477.         {    
  478.         gxViewGroup group    = GXNewViewGroup();
  479.         gxViewDevice device    = GXNewViewDevice(group, bitShape);
  480.         gxViewPort port        = GXNewViewPort(group);
  481.         gxTransform trans    = GXCloneTransform(GXGetShapeTransform(source));
  482.  
  483.         GXSetShapeAttributes(source, GXGetShapeAttributes(source) | gxMapTransformShape);
  484.         GXMoveShape(source, -bounds.left, -bounds.top);
  485.         GXSetViewPortDither(port, 4);
  486.         GXSetShapeViewPorts(source, 1, &port);
  487.         GXDrawShape(source);
  488.         GXSetShapeTransform(source, trans);
  489.         GXDisposeTransform(trans);
  490.         
  491.         GXDisposeViewGroup(group);    /* this disposes the gxViewPort and gxViewDevice */
  492.         GXDisposeShape(bitShape);
  493.         }
  494.  
  495.     {    
  496.         GrafPtr    thePort;
  497.         BitMap    srcBits;
  498.     
  499.         GetPort(&thePort);
  500.         srcBits.baseAddr = bitmap.image;
  501.         srcBits.rowBytes = bitmap.rowBytes;
  502.         srcBits.bounds = shortBounds;
  503.  
  504.         thePicture = OpenPicture(&shortBounds);
  505.         CopyBits(&srcBits, &thePort->portBits, &shortBounds, &shortBounds, srcOr, nil);
  506.         ClosePicture();
  507.     }
  508.     
  509.     DisposePtr((Ptr)bitmap.image);
  510.     
  511.     return thePicture;
  512.     
  513. } // ShapeToPICT
  514.  
  515.  
  516.  
  517. // --------------------------------------------------------------------------------------------------------------
  518.  
  519. static void GetRidOfAnyQDShapeTags(gxShape shape)
  520. {
  521.     gxShapeType shapeType = GXGetShapeType(shape);
  522.  
  523.     if (shapeType == gxPictureType)
  524.         {    
  525.         long        index, count;
  526.         gxShape        contentShape;
  527.     
  528.         count = GXGetPicture(shape, nil, nil, nil, nil);
  529.         for (index = 0; index < count; index++)
  530.             {
  531.             GXGetPictureParts(shape, index+1, 1, &contentShape, nil, nil, nil);
  532.             GetRidOfAnyQDShapeTags(contentShape);
  533.             }
  534.         }
  535.     else 
  536.         {
  537.         if ( (shapeType == gxRectangleType) && (GXGetShapeTags(shape, gxQuickDrawPictTag, 1, gxSelectToEnd, nil) > 0) )
  538.             GXSetShapeType(shape, gxPictureType);
  539.         }
  540.             
  541. } // GetRidOfAnyQDShapeTags
  542.  
  543. // --------------------------------------------------------------------------------------------------------------
  544.  
  545. static void ShapeToScrap(gxShape source)
  546. /*
  547.  *    This guy puts a Quickdraw picture on the clipboard containing an embedded shape
  548.  *    and, if addProxie is true, a 1-bit bitmap of the shape. Call this in response to
  549.  *    the user choosing "Copy" or "Cut" from the Edit menu. See comment for DecompressShape
  550.  *    to explain forPrintingOnly.
  551. */
  552. {
  553.     PicHandle    picture, proxy;
  554.     
  555.     proxy = ShapeToPICT(source);
  556.     picture = DecompressShape(source, proxy, false, true);
  557.     if (proxy)
  558.         KillPicture(proxy);
  559.  
  560.     if (picture)
  561.         {    
  562.         HLock((Handle)picture);
  563.         ZeroScrap();
  564.         PutScrap(GetHandleSize((Handle)picture), 'PICT', (Ptr)*picture);
  565.         KillPicture(picture);
  566.         }
  567.         
  568. } // ShapeToScrap
  569.  
  570. // --------------------------------------------------------------------------------------------------------------
  571.  
  572. static void CullShape(gxShape shape, gxShape addToThis, gxRectangle *pCullRect, gxStyle cullStyle, gxInk cullInk, gxTransform cullTransform)
  573. /*
  574.     Add to "addToThis" the "shape", only if the shape intersects the pCullRect.
  575. */
  576. {
  577.     gxShapeType shapeType = GXGetShapeType(shape);
  578.  
  579.     if (shapeType == gxPictureType)
  580.         {    
  581.         long        index, count;
  582.         gxShape        contentShape;
  583.     
  584.         count = GXGetPicture(shape, nil, nil, nil, nil);
  585.         for (index = 0; index < count; index++)
  586.             {
  587.             GXGetPictureParts(shape, index+1, 1, &contentShape, &cullStyle, &cullInk, &cullTransform);
  588.             CullShape(contentShape, addToThis, pCullRect, cullStyle, cullInk, cullTransform);
  589.             }
  590.         }
  591.     else 
  592.         {
  593.         gxRectangle    bounds;
  594.         
  595.         GXGetShapeLocalBounds(shape, &bounds);
  596.         
  597.         if (IsSomewhereInRectangle(pCullRect, &bounds))
  598.             {
  599.             if ( (shapeType == gxRectangleType) && (GXGetShapeTags(shape, gxQuickDrawPictTag, 1, gxSelectToEnd, nil) > 0) )
  600.                 {
  601.                 // convert shape and add -- but only if it goes okay
  602.                 GXSetShapeType(shape, gxPictureType);
  603.                 if (GXGetShapeType(shape) == gxPictureType)
  604.                     CullShape(shape, addToThis, pCullRect, cullStyle, cullInk, cullTransform);
  605.                 }
  606.             else
  607.                 {
  608.                 GXSetPictureParts(addToThis, 0, 0, 1, &shape, &cullStyle, &cullInk, &cullTransform);
  609.                 }
  610.             }
  611.         }
  612.         
  613. } // CullShape
  614.  
  615. // --------------------------------------------------------------------------------------------------------------
  616. static gxShape CullPicture(gxShape pictureShape, gxRectangle * pCullRect)
  617. /*
  618.     Returns a new shape that is all of the shapes inside of pictureShape
  619.     that intersect pCullRect.
  620. */
  621. {
  622.     gxShape        newPicture = GXNewShape(gxPictureType);
  623.     gxShape     clipShape = GXNewRectangle(pCullRect);
  624.     gxMapping    mapping;
  625.     gxRectangle    clipRect;
  626.     
  627.     // new shape as same mapping as old one
  628.     GXGetTransformMapping(GXGetShapeTransform(pictureShape), &mapping);
  629.     GXSetShapeMapping(newPicture, &mapping);
  630.     
  631.     // clip also has the mapping, but inverted so that it's the right space
  632.     InvertMapping(&mapping, &mapping);
  633.     GXMapShape(clipShape, &mapping);
  634.     GXGetShapeLocalBounds(clipShape, &clipRect);
  635.     
  636.     // clip to the selection
  637.     GXSetShapeClip(newPicture, clipShape);
  638.     GXDisposeShape(clipShape);
  639.  
  640.     // add all shapes that intersect the clip area
  641.     CullShape(pictureShape, newPicture, &clipRect, nil, nil, nil);
  642.         
  643.     // new shape is zero based
  644.     GXMoveShape(newPicture, -pCullRect->left, -pCullRect->top);
  645.     
  646.     return(newPicture);
  647.     
  648. } // CullPicture
  649.  
  650. // --------------------------------------------------------------------------------------------------------------
  651. static gxShape GetSelectedShape(WindowDataPtr pData)
  652. /*
  653.     Returns a shape that represents all shapes on the current page
  654.     that are contained by the current selection rectangle.
  655. */
  656. {
  657.     gxRectangle        cullRect;
  658.     gxShape            cullShape;
  659.     gxPoint            offset;
  660.     Fixed            zoomFactor = ((GXDataPtr)pData)->zoomFactor;
  661.     
  662.     // calculate the actual coodinate space, removing margins
  663.     {
  664.     gxRectangle        pageSize, paperSize;
  665.     
  666.     GetCurrentPageAndPaper(pData, &pageSize, &paperSize);
  667.     offset.y = FixedMultiply(-paperSize.top, zoomFactor);
  668.     offset.x = FixedMultiply(-paperSize.left, zoomFactor);
  669.     }
  670.     
  671.     // calculate the actual coodinates to copy
  672.     cullRect.top    = FixedDivide(ff(((GXDataPtr)pData)->selectionRectangle.top) - offset.y, zoomFactor);
  673.     cullRect.left    = FixedDivide(ff(((GXDataPtr)pData)->selectionRectangle.left) - offset.x, zoomFactor);
  674.     cullRect.bottom    = FixedDivide(ff(((GXDataPtr)pData)->selectionRectangle.bottom) - offset.y, zoomFactor);
  675.     cullRect.right    = FixedDivide(ff(((GXDataPtr)pData)->selectionRectangle.right) - offset.x, zoomFactor);
  676.     
  677.     // chop the data
  678.     cullShape = CullPicture(((GXDataPtr)pData)->currentPageShape, &cullRect);
  679.     
  680.     return(cullShape);
  681.     
  682. } // GetSelectedShape
  683.  
  684. // --------------------------------------------------------------------------------------------------------------
  685. static pascal OSErr GXSendDataProc(FlavorType theType, void *dragSendRefCon,
  686.                                 ItemReference theItem, DragReference theDrag)
  687. /*
  688.  *    The ItemReference is the gxShape to be sent. The dragSendRefCon is ignored.
  689. */
  690. {
  691. #pragma unused (dragSendRefCon)
  692.  
  693.     OSErr    result = noErr;
  694.     gxShape    shape = ((GXDataPtr)theItem)->tempDragShape;
  695.     
  696.     // haven't made clipped version yet?
  697.     if (shape == nil)
  698.         {
  699.         shape = GetSelectedShape((WindowDataPtr) theItem);
  700.         ((GXDataPtr)theItem)->tempDragShape = shape;
  701.         }
  702.         
  703.     switch (theType) 
  704.         {
  705.         case 'qdgx':
  706.             {    
  707.             Handle         flat;
  708.               userSpool     block;
  709.  
  710.             block.spool.spoolProcedure = gHandleSpoolProc;
  711.             block.spool.buffer = nil;
  712.             block.spool.bufferSize = 0;
  713.             GXFlattenShape(shape, gxFontListFlatten | gxFontGlyphsFlatten | gxFontVariationsFlatten, &block.spool);
  714.             flat = (Handle) block.data;
  715.     
  716.             if (flat)
  717.                 {    
  718.                 HLock(flat);
  719.                 result = SetDragItemFlavorData(theDrag, theItem, 'qdgx', *flat, GetHandleSize(flat), 0);
  720.                 DisposeHandle(flat);
  721.                 }
  722.             }
  723.             break;
  724.             
  725.         case 'PICT':
  726.             {    
  727.             PicHandle proxie = ShapeToPICT(shape);
  728.             PicHandle pict = DecompressShape(shape, proxie, false, true);
  729.     
  730.             if (proxie)
  731.                 KillPicture(proxie);
  732.             if (pict)
  733.                 {    
  734.                 HLock((Handle)pict);
  735.                 result = SetDragItemFlavorData(theDrag, theItem, 'PICT', (Ptr)*pict, GetHandleSize((Handle)pict), 0);
  736.                 KillPicture(pict);
  737.                 }
  738.             }
  739.             break;
  740.             
  741.         default:
  742.             result = badDragFlavorErr;
  743.             break;
  744.         }
  745.             
  746.     return result;
  747.     
  748. } // GXSendDataProc
  749.  
  750. #if GENERATINGCFM
  751.     static RoutineDescriptor gGXSendDataProcRD = BUILD_ROUTINE_DESCRIPTOR(uppDragSendDataProcInfo, GXSendDataProc);
  752.     static DragSendDataUPP gGXSendDataProc = &gGXSendDataProcRD;
  753. #else
  754.     static DragSendDataUPP gGXSendDataProc = NewDragSendDataProc(GXSendDataProc);
  755. #endif
  756.  
  757. // --------------------------------------------------------------------------------------------------------------
  758. static void ClearCurrentSelection(GXDataPtr pData)
  759. {
  760.     pData->currentShapeIndex = 0;
  761.     pData->currentShapeStart = 0;
  762.     pData->currentShapeEnd = 0;
  763.     if (pData->currentSelectionShape)
  764.         {
  765.         GXDisposeShape(pData->currentSelectionShape);
  766.         pData->currentSelectionShape = nil;
  767.         }
  768.         
  769. } // ClearCurrentSelection
  770.  
  771. // --------------------------------------------------------------------------------------------------------------
  772. static OSErr    GetCurrentPage(GXDataPtr pData, Boolean disposeOfSelection)
  773. /*
  774.     Disposes of previously loaded page information, and loads the
  775.     page information for the current page number.
  776. */
  777. {
  778.     OSErr        anErr;
  779.     LongRect    oldRect, newRect;
  780.     
  781.     if (pData->numberOfPages != 0)
  782.         {
  783.         // get rid of any previous format
  784.         if (pData->currentPageFormat)
  785.             {
  786.             GXDisposeFormat(pData->currentPageFormat);
  787.             pData->currentPageFormat = nil;
  788.             }
  789.             
  790.         // get rid of any previous shape
  791.         if (pData->currentPageShape)
  792.             {
  793.             GXDisposeShape(pData->currentPageShape);
  794.             pData->currentPageShape = nil;
  795.             }
  796.             
  797.         // get rid of selection, if desired
  798.         if (disposeOfSelection)
  799.             ClearCurrentSelection(pData);
  800.  
  801.         GXGetDocumentRect((WindowRef)pData, (WindowDataPtr)pData, &oldRect, false);
  802.         
  803.         GXReadPrintFilePage(pData->thePrintFile, 
  804.             pData->currentPage, 
  805.             1, &pData->childViewPort, 
  806.             &pData->currentPageFormat, &pData->currentPageShape);
  807.         }
  808.         
  809.     anErr = GXGetJobError(pData->w.hPrint);
  810.     
  811.     if (anErr == noErr)
  812.         {
  813.         GXGetDocumentRect((WindowRef)pData,(WindowDataPtr) pData, &newRect, false);
  814.         
  815.         if     (
  816.             (oldRect.left != newRect.left) ||
  817.             (oldRect.top != newRect.top) ||
  818.             (oldRect.right != newRect.right) ||
  819.             (oldRect.bottom != newRect.bottom)
  820.             )
  821.             {
  822.             // if the resulting page is < the current window size, we need to resize,
  823.             long newWidth     = newRect.right - newRect.left + kScrollBarSize;
  824.             long newHeight     = newRect.bottom - newRect.top + kScrollBarSize;
  825.             long oldWidth     = pData->w.theWindow.port.portRect.right - pData->w.theWindow.port.portRect.left;
  826.             long oldHeight     = pData->w.theWindow.port.portRect.bottom - pData->w.theWindow.port.portRect.top;
  827.             
  828.             // but don't let it get too small!
  829.             if (newWidth < pData->w.minHSize)
  830.                 newWidth = pData->w.minHSize;
  831.             if (newHeight < kMinGXDocSize)
  832.                 newHeight = kMinGXDocSize;
  833.                 
  834.             if     (
  835.                 (newWidth < oldWidth) ||
  836.                 (newHeight < oldHeight)
  837.                 )
  838.                 {
  839.                 if (newWidth > oldWidth)
  840.                     newWidth = oldWidth;
  841.                 if (newHeight > oldHeight)
  842.                     newHeight = oldHeight;
  843.                     
  844.                 SizeWindow((WindowRef)pData, newWidth, newHeight, false);
  845.                 }
  846.                 
  847.             // and in any case, the scroll bars should update
  848.             AdjustScrollBars((WindowRef)pData, true, true, nil);
  849.             }
  850.         }
  851.         
  852.     return(anErr);
  853.     
  854. } // GetCurrentPage
  855.  
  856. // --------------------------------------------------------------------------------------------------------------
  857. #define charBullet    '•'
  858.  
  859. static void GetIntlTokenChar(short whichToken, short whichScript, char *bulletString)
  860. //
  861. // GetIntlTokenChar
  862. //
  863. // This routine gets a character out of the itl4 given a script and token…
  864. //
  865. {
  866.     Handle    itl4H;
  867.     long    offset, len;
  868.  
  869.     // default the value
  870.     bulletString[0] = 1;
  871.     bulletString[1] = charBullet;
  872.     
  873.     // Look up the untoken table -- bail if we can’t get it
  874.     GetIntlResourceTable(whichScript, iuUnTokenTable, &itl4H, &offset, &len);
  875.     if (itl4H && (offset > 0) && (len >= 0))
  876.     {
  877.         char *sp = (*itl4H + offset);                // Point to start of untoken table
  878.         if (whichToken <= ((short *)sp)[1])            // Check if token has valid index
  879.         {
  880.             sp += ((short *)sp)[2+whichToken];        // Add the string offset and voliá!
  881.             BlockMoveData(sp, bulletString, sp[0]+1);
  882.         }
  883.     }
  884.     
  885. } // GetIntlTokenChar
  886.  
  887. // --------------------------------------------------------------------------------------------------------------
  888. // This code is required to change pop up menus to a different font size.  It would be
  889. // better to use the pop up control, but it doesn't allow multiple items to be marked.
  890.  
  891. #define SysFontSize    0xBA8
  892. #define SysFontFam    0xBA6
  893. #define CurFMInput    0x988
  894.  
  895. static void DoUseWFont(TextState *savedInfo, WindowRef owner,  Boolean saveIt)
  896. /*************************************************************
  897.     DoUseWFont        - Sets the font mgr low mem globals so
  898.                         we can have Geneva 9 popups
  899.  
  900.         savedInfo    - Fills it in if saveIt = true, else
  901.                         it sets the port to those values
  902.         owner        - Where to get the original values
  903.         saveIt        - true for save
  904. **************************************************************/
  905. {
  906.     TextState        myState,
  907.                     *theState;
  908.     short            aFont;
  909.  
  910.     theState = savedInfo;
  911.  
  912.     if (saveIt) 
  913.         {
  914.         savedInfo->theFont = GetSysFont();    // save low memory globals
  915.         savedInfo->theSize = *((short *) SysFontSize);
  916.  
  917.         myState.theFont = GetWindowPort(owner)->txFont;
  918.         myState.theSize = GetWindowPort(owner)->txSize;
  919.         theState = &myState;
  920.  
  921.         // if we stuff systemFont, it will screw up Script Mgr
  922.         if (GetWindowPort(owner)->txFont == systemFont)
  923.             goto dosizestuff;
  924.         }
  925.  
  926.     // if we stuff applFont, this will also screw up Script Mgr
  927.     // instead we get the actual font
  928.     aFont = theState->theFont;
  929.     if (saveIt)
  930.         if (GetWindowPort(owner)->txFont == applFont)
  931.             aFont = GetAppFont();
  932.     *((short *) SysFontFam) = aFont;                    // set/restore low memory globals
  933.  
  934. dosizestuff:
  935.     *((short *) SysFontSize) = theState->theSize;
  936.  
  937.     *((long *) CurFMInput) = 0xFFFFFFFF;
  938.     
  939. } // DoUseWFont
  940.  
  941.  
  942. // --------------------------------------------------------------------------------------------------------------
  943.  
  944. static void SetZoom(WindowRef pWindow, WindowDataPtr pData, Fixed newZoom)
  945. /*
  946.     Sets the new zoom factor for the window, causing an update for
  947.     the window if required.
  948. */
  949. {
  950.     Fixed    scaleFactor;
  951.     
  952.     // pin to max/min zoom factors
  953.     if (newZoom > ff(32))
  954.         newZoom = ff(32);
  955.     if (newZoom < 0x0800)
  956.         newZoom = 0x0800;
  957.     
  958.     scaleFactor = FixedDivide(newZoom, ((GXDataPtr)pData)->zoomFactor);
  959.     
  960.     if (scaleFactor != ff(1))
  961.         {
  962.         gxPoint        centerPoint;
  963.         GrafPtr        pPort = (GrafPtr)GetWindowPort(pWindow);
  964.         
  965.         // zoom about the window center
  966.         centerPoint.x = ff(pPort->portRect.left + (RectWidth(pPort->portRect) >> 1));
  967.         centerPoint.y = ff(pPort->portRect.top + (RectHeight(pPort->portRect) >> 1));
  968.         
  969.         // new zoom active
  970.         ((GXDataPtr)pData)->zoomFactor = newZoom;
  971.         
  972.         // force update and recalc the size of window
  973.         InvalRect(&pPort->portRect);
  974.         AdjustScrollBars(pWindow, true, true, nil);
  975.  
  976.          // scale scroll values
  977.         SetControlValue(pData->hScroll, FixedToInt( FixedDivide(centerPoint.x, scaleFactor) + FixedMultiply(ff(GetControlValue(pData->hScroll)), scaleFactor) ) );
  978.         SetControlValue(pData->vScroll, FixedToInt( FixedDivide(centerPoint.y, scaleFactor) + FixedMultiply(ff(GetControlValue(pData->vScroll)), scaleFactor) ) );
  979.         
  980.         // zoom the selection
  981.         ((GXDataPtr)pData)->selectionRectangle.left     = FixedToInt (FixedMultiply(ff(((GXDataPtr)pData)->selectionRectangle.left), scaleFactor) );
  982.         ((GXDataPtr)pData)->selectionRectangle.top         = FixedToInt (FixedMultiply(ff(((GXDataPtr)pData)->selectionRectangle.top), scaleFactor) );
  983.         ((GXDataPtr)pData)->selectionRectangle.right     = FixedToInt (FixedMultiply(ff(((GXDataPtr)pData)->selectionRectangle.right), scaleFactor) );
  984.         ((GXDataPtr)pData)->selectionRectangle.bottom     = FixedToInt (FixedMultiply(ff(((GXDataPtr)pData)->selectionRectangle.bottom), scaleFactor) );
  985.         }
  986.     
  987. } // SetZoom
  988.  
  989. // --------------------------------------------------------------------------------------------------------------
  990.  
  991. static void SetShapeGreyColorLevel(gxShape thisShape, unsigned long greyLevel)
  992. {
  993.     gxColor thisColor;
  994.  
  995.     thisColor.space = gxGraySpace;
  996.     thisColor.profile = nil;
  997.     thisColor.element.gray = greyLevel;
  998.     GXSetShapeColor(thisShape, &thisColor);
  999.     
  1000. } // SetShapeGreyColorLevel
  1001.  
  1002. // --------------------------------------------------------------------------------------------------------------
  1003. static void    CenterRect(Rect *source, Rect *against)
  1004. /*
  1005.     Centers "source" within or around "against".
  1006. */
  1007. {
  1008.     // center picture if requested
  1009.     short    height, width, pheight, pwidth;
  1010.     
  1011.     height = (against->bottom - against->top) >> 1;
  1012.     width = (against->right - against->left) >> 1;
  1013.     pheight = (source->bottom - source->top) >> 1;
  1014.     pwidth = (source->right - source->left) >> 1;
  1015.     
  1016.     source->top = against->top + height - pheight;
  1017.     source->bottom = against->bottom - height + pheight;
  1018.     source->left = against->left + width - pwidth;
  1019.     source->right = against->right - width + pwidth;
  1020.  
  1021. } // CenterRect
  1022.  
  1023. // --------------------------------------------------------------------------------------------------------------
  1024.  
  1025. static gxShape FindNestedIndexedLayout(gxShape shape, 
  1026.                     long searchIndex, long * pIndex, gxMapping *pConcatMapping)
  1027. /*
  1028.     Returns the shape represented by "searchIndex" shapes into the picture,
  1029.     sequentially, including all nestings of pictures.  Uses pIndex as
  1030.     work storage, which must be initialized to zero before the call.
  1031.     
  1032.     Returns shape found, or NIL if the searchIndex is larger than
  1033.     the number of shapes in the picture.  If NIL is returned,
  1034.     then the contents of pIndex will contain the number of
  1035.     shapes in the picture.
  1036. */
  1037. {
  1038.     gxShape        returnShape = nil;
  1039.     gxShapeType shapeType = GXGetShapeType(shape);
  1040.  
  1041.     // bail on negative index
  1042.     if (searchIndex < 0)
  1043.         return(nil);
  1044.         
  1045.     if (shapeType == gxPictureType)
  1046.         {    
  1047.         long        index, count;
  1048.         gxShape        contentShape;
  1049.         gxTransform    contentTransform;
  1050.         gxMapping    contentMapping;
  1051.         
  1052.         count = GXGetPicture(shape, nil, nil, nil, nil);
  1053.         for (index = 0; index < count; index++)
  1054.             {
  1055.             GXGetPictureParts(shape, index+1, 1, &contentShape, nil, nil, &contentTransform);
  1056.             
  1057.             returnShape = FindNestedIndexedLayout(contentShape, searchIndex, pIndex, pConcatMapping ? &contentMapping : nil);
  1058.             if (returnShape)
  1059.                 {
  1060.                 if (pConcatMapping)
  1061.                     {
  1062.                     if (!contentTransform)
  1063.                         contentTransform = GXGetShapeTransform(contentShape);
  1064.                     GXGetTransformMapping(contentTransform, &contentMapping);
  1065.                     MapMapping(&contentMapping, pConcatMapping);
  1066.                     *pConcatMapping = contentMapping;
  1067.                     }
  1068.                 break;
  1069.                 }
  1070.             }
  1071.         }
  1072.     else 
  1073.         {
  1074.         if ( (shapeType == gxLayoutType) || (shapeType == gxGlyphType) || (shapeType == gxTextType) )
  1075.             {
  1076.             (*pIndex)++;
  1077.             if (searchIndex == *pIndex)
  1078.                 returnShape = shape;
  1079.             }
  1080.         }
  1081.         
  1082.     return(returnShape);
  1083.     
  1084. } // FindNestedIndexedLayout
  1085.  
  1086. // --------------------------------------------------------------------------------------------------------------
  1087. static Boolean PerformNextFind(WindowRef pWindow, WindowDataPtr pData,
  1088.                 Str255 findString,
  1089.                 Boolean caseSensitive,
  1090.                 Boolean backwards,
  1091.                 Boolean wraparound)
  1092. {
  1093.     Boolean    foundSomething = false;
  1094.     long    searchIndex, workIndex;
  1095.     gxShape    aShape;
  1096.     long    direction;
  1097.     long    oldPageNumber = ((GXDataPtr)pData)->currentPage;
  1098.     long    endPageNumber;
  1099.     Boolean    firstTime = true;
  1100.     gxMapping    concatMapping;
  1101.     
  1102.     // initialize direction of the walk
  1103.     if (backwards)
  1104.         direction = -1;
  1105.     else
  1106.         direction = 1;
  1107.     
  1108.     // start searching where we last left off    
  1109.     searchIndex = ((GXDataPtr)pData)->currentShapeIndex;
  1110.     if (searchIndex != 0)
  1111.         searchIndex -= direction;
  1112.     
  1113.     if (((GXDataPtr)pData)->numberOfPages == 1)
  1114.         wraparound = false;
  1115.  
  1116.     // end searching on a particular page
  1117.     if (backwards)
  1118.         endPageNumber = 0;
  1119.     else
  1120.         endPageNumber = ((GXDataPtr)pData)->numberOfPages + 1;
  1121.     
  1122.     // can't search on qd shapes, so we get rid of them
  1123.     GetRidOfAnyQDShapeTags(((GXDataPtr)pData)->currentPageShape);
  1124.  
  1125.     do
  1126.         {
  1127.         // search for the next shape or prev shape
  1128.         searchIndex += direction;
  1129.         
  1130.         // initialize the working index so that we know traversal level
  1131.         workIndex = 0;
  1132.         
  1133.         // initialize the mapping to identity
  1134.         ResetMapping(&concatMapping);
  1135.         GXGetShapeMapping(((GXDataPtr)pData)->currentPageShape, &concatMapping);
  1136.         
  1137.         // find the next layout in the page
  1138.         aShape = FindNestedIndexedLayout(((GXDataPtr)pData)->currentPageShape, searchIndex, &workIndex, &concatMapping);
  1139.         if (aShape)
  1140.             {
  1141.             gxShapeType shapeType = GXGetShapeType(aShape);
  1142.             long          size;
  1143.             Handle        aHandle;
  1144.             
  1145.             // determine size and allocate storage for layout contents
  1146.             switch (shapeType)
  1147.                 {
  1148.                 case gxTextType:
  1149.                     size = GXGetText(aShape, nil, nil, nil);
  1150.                     break;
  1151.                 case gxGlyphType:
  1152.                     size = GXGetGlyphs(aShape, nil, nil, nil,
  1153.                                     nil, nil, nil, nil, nil);
  1154.                     break;
  1155.                 case gxLayoutType:
  1156.                     size = GXGetLayout(aShape, nil,
  1157.                                     nil, nil, nil,     // styles
  1158.                                     nil, nil, nil,     // levels
  1159.                                     nil, nil);        // options/position
  1160.                     break;
  1161.                 }
  1162.             aHandle = NewHandle(size);
  1163.             
  1164.             if (aHandle)
  1165.                 {
  1166.                 long newStart, newEnd;
  1167.                 
  1168.                 // grab the contents of the layout into the temp storage
  1169.                 HLock(aHandle);
  1170.                 switch (shapeType)
  1171.                     {
  1172.                     case gxTextType:
  1173.                         GXGetText(aShape, nil, (unsigned char*)*aHandle, nil);
  1174.                         break;
  1175.                     case gxGlyphType:
  1176.                         GXGetGlyphs(aShape, nil,  (unsigned char*)*aHandle, nil,
  1177.                                         nil, nil, nil, nil, nil);
  1178.                         break;
  1179.                     case gxLayoutType:
  1180.                         GXGetLayout(aShape,  (unsigned char*)*aHandle,
  1181.                                     nil, nil, nil,     // styles
  1182.                                     nil, nil, nil,     // levels
  1183.                                     nil, nil);        // options/position
  1184.                         break;
  1185.                     }
  1186.                 HUnlock(aHandle);
  1187.                 
  1188.                 // search the handle for the string we're looking for,
  1189.                 // but don't wraparound because we handle that over layout
  1190.                 // ranges and pages ourselves
  1191.                 {
  1192.                 long offset;
  1193.                 
  1194.                 if ((firstTime) && (((GXDataPtr)pData)->currentSelectionShape))
  1195.                     {
  1196.                     // for shape that we have found something in before
  1197.                     // start at end of last point if forwards, start of last point
  1198.                     // if backwards
  1199.                     firstTime = false;
  1200.                     offset = backwards ? ((GXDataPtr)pData)->currentShapeStart : ((GXDataPtr)pData)->currentShapeEnd;
  1201.                     }
  1202.                 else
  1203.                     {
  1204.                     // for "new" shape we haven't hit before, start at
  1205.                     // begining for forwards, end for backwards
  1206.                     offset = backwards ? size : 0;
  1207.                     }
  1208.                     
  1209.                 foundSomething = PerformSearch(aHandle, offset, findString, 
  1210.                             caseSensitive, backwards, false,
  1211.                             &newStart, &newEnd);
  1212.                 }
  1213.                             
  1214.                 // done with our temp storage
  1215.                 DisposeHandle(aHandle);
  1216.                 
  1217.                 // got it?  then mark it and bail out
  1218.                 if (foundSomething)
  1219.                     {
  1220.                     // remember where we are in the page
  1221.                     ((GXDataPtr)pData)->currentShapeIndex = searchIndex;
  1222.                     
  1223.                     // what offsets the selection is
  1224.                     ((GXDataPtr)pData)->currentShapeStart = newStart;
  1225.                     ((GXDataPtr)pData)->currentShapeEnd = newEnd;
  1226.                     
  1227.                     // and the shape containing the selection
  1228.                     if (((GXDataPtr)pData)->currentSelectionShape)
  1229.                         GXDisposeShape(((GXDataPtr)pData)->currentSelectionShape);
  1230.                     ((GXDataPtr)pData)->currentSelectionShape = GXCloneShape(aShape);
  1231.                     ((GXDataPtr)pData)->currentSelectionMapping = concatMapping;
  1232.                     break;
  1233.                     } // found the string
  1234.                     
  1235.                 } // allocated the handle
  1236.                 
  1237.             } // found a shape
  1238.         else
  1239.             {
  1240.             OSErr    anErr = noErr;
  1241.             
  1242.             // didn't find it on this page, move on
  1243.             ((GXDataPtr)pData)->currentPage += direction;
  1244.             
  1245.                 
  1246.             // clamp to the ends of the range
  1247.             if (backwards)
  1248.                 {
  1249.                 if (((GXDataPtr)pData)->currentPage <= endPageNumber)
  1250.                     {
  1251.                     if (wraparound)
  1252.                         {
  1253.                         ((GXDataPtr)pData)->currentPage = ((GXDataPtr)pData)->numberOfPages;
  1254.                         endPageNumber = oldPageNumber;
  1255.                         wraparound = false;
  1256.                         }
  1257.                     else
  1258.                         anErr = paramErr;
  1259.                     }
  1260.                 }
  1261.             else
  1262.                 {
  1263.                 if (((GXDataPtr)pData)->currentPage >= endPageNumber)
  1264.                     {
  1265.                     if (wraparound)
  1266.                         {
  1267.                         ((GXDataPtr)pData)->currentPage = 1;
  1268.                         endPageNumber = oldPageNumber;
  1269.                         wraparound = false;
  1270.                         }
  1271.                     else
  1272.                         anErr = paramErr;
  1273.                     }
  1274.                 }
  1275.                 
  1276.             // fetch contents
  1277.             if (anErr == noErr)
  1278.                 anErr = GetCurrentPage((GXDataPtr) pData, false);
  1279.                 
  1280.             // anything wrong?  then all done searching
  1281.             if (anErr != noErr)
  1282.                 {
  1283.                 break;
  1284.                 }
  1285.             else
  1286.                 {
  1287.                 GetRidOfAnyQDShapeTags(((GXDataPtr)pData)->currentPageShape);
  1288.                 if (backwards)
  1289.                     {
  1290.                     workIndex = 0;
  1291.                     (void) FindNestedIndexedLayout(((GXDataPtr)pData)->currentPageShape, 0x7FFFFFF, &workIndex, nil);
  1292.                     searchIndex = workIndex;
  1293.                     }
  1294.                 else
  1295.                     searchIndex = 0;
  1296.                 }
  1297.             }
  1298.         } while (!foundSomething);
  1299.     
  1300.     // if we found something, force and update.  If not, make sure
  1301.     // that the current page is restored to the page we had when 
  1302.     // coming in.
  1303.     if (foundSomething)
  1304.         {
  1305.         InvalRect(&GetWindowPort(pWindow)->portRect);
  1306.         }
  1307.     else
  1308.         {
  1309.         if (oldPageNumber != ((GXDataPtr)pData)->currentPage)
  1310.             {
  1311.             ((GXDataPtr)pData)->currentPage = oldPageNumber;
  1312.             GetCurrentPage((GXDataPtr) pData, false);
  1313.             }
  1314.         }
  1315.     return(foundSomething);
  1316.     
  1317. } // PerformNextFind
  1318.  
  1319. // --------------------------------------------------------------------------------------------------------------
  1320. static gxShape GetCurrentSelectionHighlight(WindowDataPtr pData, Boolean mapIt)
  1321. {
  1322.     gxShape        highlight;
  1323.     
  1324.     highlight = GXGetLayoutHighlight(((GXDataPtr)pData)->currentSelectionShape, 
  1325.                         ((GXDataPtr)pData)->currentShapeStart, ((GXDataPtr)pData)->currentShapeEnd,
  1326.                         gxHighlightAverageAngle, nil);
  1327.                         
  1328.     
  1329.     if (mapIt)
  1330.         GXMapShape(highlight, &((GXDataPtr)pData)->currentSelectionMapping);
  1331.     
  1332.     // draw and dispose of the highlight
  1333.     GXSetShapeViewPorts(highlight, 1, &((GXDataPtr)pData)->childViewPort);
  1334.     GXSetShapeFill(highlight, gxClosedFrameFill);
  1335.     GXSetShapeClip(highlight, nil);
  1336.  
  1337.     return(highlight);
  1338.     
  1339. } // GetCurrentSelectionHighlight
  1340.  
  1341. // --------------------------------------------------------------------------------------------------------------
  1342. static void ScrollFoundShapeIntoView(WindowRef pWindow, WindowDataPtr pData)
  1343. {
  1344.     gxRectangle    bounds;
  1345.     Point        scrollAmount;
  1346.     Point        controlValues;
  1347.     gxRectangle    windowBounds;
  1348.     GrafPtr        pPort = (GrafPtr)GetWindowPort(pWindow);
  1349.     
  1350.     if ( ! (((GXDataPtr)pData)->currentSelectionShape) )
  1351.         return;
  1352.         
  1353.     // cache scroll state
  1354.     controlValues.h = GetControlValue(pData->hScroll);
  1355.     controlValues.v = GetControlValue(pData->vScroll);
  1356.     
  1357.     // calculate visible bounds of window
  1358.     windowBounds.left         = ff(pPort->portRect.left + controlValues.h);
  1359.     windowBounds.right         = ff(pPort->portRect.right - kScrollBarSize + controlValues.h);
  1360.     windowBounds.top         = ff(pPort->portRect.top + controlValues.v);
  1361.     windowBounds.bottom     = ff(pPort->portRect.bottom - kScrollBarSize + controlValues.v);                
  1362.  
  1363.     // grab the bounds of the shape, add on the margins, scale to zoom factor
  1364.     {
  1365.     gxRectangle        pageSize, paperSize;
  1366.     gxShape            highlight = GetCurrentSelectionHighlight(pData, false);
  1367.     
  1368.     GXGetShapeBounds(highlight, 0, &bounds);
  1369.     GXDisposeShape(highlight);
  1370.     GetCurrentPageAndPaper(pData, &pageSize, &paperSize);
  1371.     bounds.left     = FixedMultiply(bounds.left - paperSize.left, ((GXDataPtr)pData)->zoomFactor);
  1372.     bounds.right     = FixedMultiply(bounds.right - paperSize.left, ((GXDataPtr)pData)->zoomFactor);
  1373.     bounds.top         = FixedMultiply(bounds.top - paperSize.top, ((GXDataPtr)pData)->zoomFactor);
  1374.     bounds.bottom     = FixedMultiply(bounds.bottom - paperSize.top, ((GXDataPtr)pData)->zoomFactor);
  1375.     }
  1376.  
  1377.     if     (
  1378.         (bounds.bottom <= windowBounds.top) ||
  1379.         (bounds.top >= windowBounds.bottom) ||
  1380.         (bounds.right <= windowBounds.left) ||
  1381.         (bounds.left >= windowBounds.right) 
  1382.         )
  1383.         {
  1384.         scrollAmount.h = controlValues.h - FixedToInt(bounds.left);
  1385.         scrollAmount.v = controlValues.v - FixedToInt(bounds.top);
  1386.         
  1387.         SetControlAndClipAmount(pData->hScroll, &scrollAmount.h);
  1388.         SetControlAndClipAmount(pData->vScroll, &scrollAmount.v);
  1389.         if ((scrollAmount.h) || (scrollAmount.v))
  1390.             DoScrollContent(pWindow, pData, scrollAmount.h, scrollAmount.v);
  1391.         }
  1392.         
  1393. } // ScrollFoundShapeIntoView
  1394.  
  1395. // --------------------------------------------------------------------------------------------------------------
  1396. static Boolean TrackIn(Rect *pTrackRect, Point clickPoint, Rect *pDrawRect, short inID, short outID)
  1397. {
  1398.     Boolean    in = false;
  1399.     
  1400.     if (PtInRect(clickPoint, pTrackRect))
  1401.         {
  1402.         in = true;
  1403.         
  1404.         PlotIconID(pDrawRect, ttNone, ttNone, inID);
  1405.         while (StillDown())
  1406.             {
  1407.             GetMouse(&clickPoint);
  1408.             
  1409.             if (PtInRect(clickPoint, pTrackRect))
  1410.                 {
  1411.                 if (!in)
  1412.                     {
  1413.                     in = true;
  1414.                     PlotIconID(pDrawRect, ttNone, ttNone, inID);
  1415.                     }
  1416.                 }
  1417.             else
  1418.                 {
  1419.                 if (in)
  1420.                     {
  1421.                     in = false;
  1422.                     PlotIconID(pDrawRect, ttNone, ttNone, outID);
  1423.                     }
  1424.                 }
  1425.             }
  1426.         }
  1427.         
  1428.     return(in);
  1429.     
  1430. } // TrackIn
  1431.  
  1432. // --------------------------------------------------------------------------------------------------------------
  1433. static void DrawPageSliderAndThumb(WindowRef pWindow, long currentValue, long maxValue)
  1434. {
  1435.     Rect        pageSliderRect;
  1436.     Rect        pageThumbRect;
  1437.     long        pixelValue;
  1438.     Str255        aString;
  1439.     FontInfo    theInfo;
  1440.     PicHandle    proxyHandle;
  1441.     Rect        proxyRect;
  1442.     GrafPtr        pPort = (GrafPtr)GetWindowPort(pWindow);
  1443.     
  1444.     // calculate location of the slider
  1445.     pageSliderRect.left     = kPageSliderMargins;
  1446.     pageSliderRect.bottom     = pPort->portRect.bottom - kPageSliderMargins;
  1447.     pageSliderRect.top         = pageSliderRect.bottom - kPageSliderHeight;
  1448.     pageSliderRect.right     = pPort->portRect.right - kPageSliderMargins;
  1449.         
  1450.     // then calculate the thumb within that slider
  1451.     pixelValue = (currentValue-1) 
  1452.                 *
  1453.                 (pageSliderRect.right - pageSliderRect.left - kPageThumbMargins*2 - kPageThumbWidth) 
  1454.                 /
  1455.                 (maxValue-1);
  1456.                 
  1457.     pageThumbRect.left         = pageSliderRect.left + kPageThumbMargins + pixelValue;
  1458.     pageThumbRect.right        = pageThumbRect.left + kPageThumbWidth;
  1459.     pageThumbRect.top        = pageSliderRect.top - kPageThumbEdge;
  1460.     pageThumbRect.bottom    = pageThumbRect.top + kPageThumbHeight;
  1461.  
  1462.     // and finally, the location to draw the proxy (if any)
  1463.     proxyRect.top            = kPageSliderMargins;
  1464.     proxyRect.bottom        = proxyRect.top + kProxyHeight;
  1465.     proxyRect.left            = pPort->portRect.left + 
  1466.                                 ((pPort->portRect.right - pPort->portRect.left) >> 1) -
  1467.                                 (kProxyWidth >> 1);
  1468.     proxyRect.right            = proxyRect.left + kProxyWidth;
  1469.     if (Count1Resources(kProxyType) == 0)
  1470.         proxyRect.bottom = proxyRect.top;
  1471.         
  1472.     // draw the slider area
  1473.     FillRect(&pageSliderRect, &qd.gray);
  1474.     FrameRect(&pageSliderRect);
  1475.  
  1476.     // erase areas above and below the slider (old thumb erase)
  1477.     {
  1478.     Rect    sliderEraseRect = pageSliderRect;
  1479.     
  1480.     ForeColor(whiteColor);
  1481.     sliderEraseRect.top = pageThumbRect.top;
  1482.     sliderEraseRect.bottom = sliderEraseRect.top + kPageThumbEdge;
  1483.     PaintRect(&sliderEraseRect);
  1484.     sliderEraseRect.bottom = pageThumbRect.bottom;
  1485.     sliderEraseRect.top = sliderEraseRect.bottom - kPageThumbEdge;
  1486.     PaintRect(&sliderEraseRect);
  1487.     }
  1488.     
  1489.     // draw the thumb
  1490.     ForeColor(blackColor);
  1491.     FrameRect(&pageThumbRect);
  1492.     InsetRect(&pageThumbRect, 1, 1);
  1493.     ForeColor(whiteColor);
  1494.     FrameRect(&pageThumbRect);
  1495.     InsetRect(&pageThumbRect, 1, 1);
  1496.     ForeColor(blackColor);
  1497.     FrameRect(&pageThumbRect);
  1498.  
  1499.     // draw page string label
  1500.     TextFace(bold);
  1501.     TextFont(applFont);
  1502.     TextSize(9);
  1503.     TextMode(srcCopy);
  1504.     GetFontInfo(&theInfo);
  1505.     
  1506.     MoveTo(pageSliderRect.left, pageThumbRect.top - kPageThumbEdge - theInfo.descent);
  1507.     GetIndString(aString, kPageControlStrings, iGoToPageString);
  1508.     DrawString(aString);
  1509.     NumToString(currentValue, aString);
  1510.     DrawString(aString);
  1511.     
  1512.     // erase any trailing digits (pretty cheezy, but seems to work)
  1513.     DrawString("\p       ");
  1514.     
  1515.     // draw the proxy, or erase the proxy area if no picture to draw
  1516.     proxyHandle = (PicHandle) GetResource(kProxyType, kProxyBaseID + currentValue - 1);
  1517.     if (proxyHandle)
  1518.         {
  1519.         Rect    drawRect;
  1520.         Fixed    scaleFactor;
  1521.         
  1522.         drawRect = (**proxyHandle).picFrame;
  1523.         
  1524.         // compute aspect ratio preserving scale
  1525.         if (RectHeight(drawRect) > RectWidth(drawRect))
  1526.             scaleFactor = FixRatio(RectHeight(proxyRect), RectHeight(drawRect));
  1527.         else
  1528.             scaleFactor = FixRatio(RectWidth(proxyRect), RectWidth(drawRect));
  1529.         drawRect.bottom = drawRect.top +
  1530.                     ( FixMul( (RectHeight(drawRect) << 16), scaleFactor) >> 16);
  1531.         drawRect.right = drawRect.left +
  1532.                     ( FixMul( (RectWidth(drawRect) << 16), scaleFactor) >> 16);
  1533.         CenterRect(&drawRect, &proxyRect);
  1534.         
  1535.         // erase the area outside of the picture, but inside of the 
  1536.         // total proxy area, because some pictures will leave whitespace on the edge
  1537.         {
  1538.         RgnHandle    rgn1 = NewRgn();
  1539.         RgnHandle    rgn2 = NewRgn();
  1540.         
  1541.         RectRgn(rgn1, &proxyRect);
  1542.         RectRgn(rgn2, &drawRect);
  1543.         DiffRgn(rgn1, rgn2, rgn1);
  1544.         EraseRgn(rgn1);
  1545.         DisposeRgn(rgn1);
  1546.         DisposeRgn(rgn2);
  1547.         }
  1548.  
  1549.         // finally, we can draw and dispose of the picture
  1550.         DrawPicture(proxyHandle, &drawRect);
  1551.         ReleaseResource((Handle) proxyHandle);
  1552.         
  1553.         }
  1554.     else
  1555.         {
  1556.         EraseRect(&proxyRect);
  1557.         }
  1558.         
  1559. } // DrawPageSliderAndThumb
  1560.  
  1561. // --------------------------------------------------------------------------------------------------------------
  1562. static OSErr    DoDrawingClick(WindowRef pWindow, WindowDataPtr pData, Point clickPoint, EventRecord *pEvent)
  1563. {
  1564. #pragma unused (pEvent, pWindow)
  1565.  
  1566.     OSErr    anErr = noErr;
  1567.     Point    lastPoint = clickPoint;
  1568.     Point    currentPoint;
  1569.     Fixed    penSize;
  1570.     gxInk    newInk = GXNewInk();
  1571.     gxStyle newStyle = GXNewStyle();
  1572.     gxShape    newShape = GXNewShape(gxPolygonType);
  1573.     long    addPoly[] = {1, 1, 0, 0};
  1574.     
  1575.     // set up the style for the shape
  1576.     GXSetStylePen(newStyle, ff(10));
  1577.     
  1578.     // and the ink for the shape
  1579.     {
  1580.     gxColor    redColor;
  1581.     gxTransferMode mode;
  1582.     
  1583.     // the color
  1584.     redColor.space        = gxRGBSpace;
  1585.     redColor.profile    = nil;
  1586.     redColor.element.rgb.red    = 0xFFFF;
  1587.     redColor.element.rgb.green    = 0x0000;
  1588.     redColor.element.rgb.blue    = 0x0000;
  1589.     GXSetInkColor(newInk, &redColor);
  1590.     
  1591.     // the transfer mode
  1592.     mode.space         = gxHSVSpace;
  1593.     mode.set        = nil;
  1594.     mode.profile    = nil;
  1595.     InitColorMatrix(mode.sourceMatrix);
  1596.     InitColorMatrix(mode.deviceMatrix);
  1597.     InitColorMatrix(mode.resultMatrix);
  1598.     mode.flags        = 0;
  1599.     
  1600.     mode.component[0].mode    = gxCopyMode;
  1601.     mode.component[0].flags    = 0;
  1602.     mode.component[0].sourceMinimum    = 0;
  1603.     mode.component[0].sourceMaximum    = gxColorValue1;
  1604.     mode.component[0].deviceMinimum    = 0;
  1605.     mode.component[0].deviceMaximum    = gxColorValue1;
  1606.     mode.component[0].clampMinimum    = 0;
  1607.     mode.component[0].clampMaximum    = gxColorValue1;
  1608.     mode.component[0].operand        = 0;
  1609.  
  1610.     mode.component[1].mode    = gxCopyMode;
  1611.     mode.component[1].flags    = 0;
  1612.     mode.component[1].sourceMinimum    = 0;
  1613.     mode.component[1].sourceMaximum    = gxColorValue1;
  1614.     mode.component[1].deviceMinimum    = 0;
  1615.     mode.component[1].deviceMaximum    = gxColorValue1;
  1616.     mode.component[1].clampMinimum    = 0;
  1617.     mode.component[1].clampMaximum    = gxColorValue1;
  1618.     mode.component[1].operand        = 0;
  1619.  
  1620.     mode.component[2].mode    = gxNoMode;
  1621.     mode.component[2].flags    = 0;
  1622.     mode.component[2].sourceMinimum    = 0;
  1623.     mode.component[2].sourceMaximum    = gxColorValue1;
  1624.     mode.component[2].deviceMinimum    = 0;
  1625.     mode.component[2].deviceMaximum    = gxColorValue1;
  1626.     mode.component[2].clampMinimum    = 0;
  1627.     mode.component[2].clampMaximum    = gxColorValue1;
  1628.     mode.component[2].operand        = 0;
  1629.     GXSetInkTransfer(newInk, &mode);
  1630.     }
  1631.     
  1632.     // set the style and ink of the shape
  1633.     GXSetShapeStyle(newShape, newStyle);
  1634.     GXSetShapeInk(newShape, newInk);
  1635.     GXSetShapeFill(newShape, gxOpenFrameFill);
  1636.     
  1637.     // initialize the first point in the shape
  1638.     addPoly[2] = ff(lastPoint.h);
  1639.     addPoly[3] = ff(lastPoint.v);
  1640.     GXSetPolygonParts(newShape, gxSelectToEnd, 1, (gxPolygons*)addPoly, gxRemoveDuplicatePointsEdit);
  1641.  
  1642.     // determine the amount we require the mouse to move before adding a new point
  1643.     penSize = FixedDivide(GXGetStylePen(newStyle), ff(2));
  1644.     if (penSize < ff(1))
  1645.         penSize = ff(1);
  1646.  
  1647.     do
  1648.         {
  1649.         GetMouse(¤tPoint);
  1650.         if     (
  1651.             (ff(ABS(currentPoint.h - lastPoint.h)) > penSize) ||
  1652.             (ff(ABS(currentPoint.v - lastPoint.v)) > penSize)
  1653.             )
  1654.             {
  1655.             // add the new point to the new shape
  1656.             lastPoint = currentPoint;
  1657.             addPoly[2] = ff(lastPoint.h);
  1658.             addPoly[3] = ff(lastPoint.v);
  1659.             GXSetPolygonParts(newShape, gxSelectToEnd, 1, (gxPolygons*)addPoly, gxRemoveDuplicatePointsEdit);
  1660.             GXDrawShape(newShape);
  1661.             }
  1662.         } while (StillDown());
  1663.     
  1664.     {
  1665.     Fixed            zoomFactor = ((GXDataPtr)pData)->zoomFactor;
  1666.     Fixed            shapeScale = FixedDivide(ff(1), zoomFactor);
  1667.     gxRectangle        pageSize, paperSize;
  1668.         
  1669.     // offset the shape by the scroll bars & margins
  1670.     GetCurrentPageAndPaper(pData, &pageSize, &paperSize);
  1671.     GXMoveShape(newShape, 
  1672.                 ff(GetControlValue(pData->hScroll)) + FixedMultiply(paperSize.left, zoomFactor),
  1673.                 ff(GetControlValue(pData->vScroll)) + FixedMultiply(paperSize.top, zoomFactor) );
  1674.  
  1675.     // scale the shape to the current scale factor
  1676.     GXScaleShape(newShape, shapeScale, shapeScale, 0, 0 );
  1677.     GXSetShapePen(newShape, FixedMultiply(GXGetShapePen(newShape), shapeScale) );
  1678.     }
  1679.     
  1680.     // add shape to the page
  1681.     {
  1682.     gxShape        annotationShape = (*((GXDataPtr)pData)->pageAnnotations)[((GXDataPtr)pData)->currentPage-1];
  1683.     
  1684.     if (!annotationShape)
  1685.         {
  1686.         annotationShape = GXNewShape(gxPictureType);
  1687.         (*((GXDataPtr)pData)->pageAnnotations)[((GXDataPtr)pData)->currentPage-1] = annotationShape;
  1688.         }
  1689.     if (annotationShape)
  1690.         GXSetPictureParts(annotationShape, 0, 0, 1, &newShape, nil, nil, nil);
  1691.     }
  1692.  
  1693.     // all done with our copies of the shape, style, and ink    
  1694.     GXDisposeShape(newShape);
  1695.     GXDisposeStyle(newStyle);
  1696.     GXDisposeInk(newInk);
  1697.     
  1698.     // we've touched the file
  1699.     pData->changed = true;
  1700.     
  1701.     return(anErr);
  1702.     
  1703. } // DoDrawingClick
  1704.  
  1705. // --------------------------------------------------------------------------------------------------------------
  1706.  
  1707. // Handle update/activate events behind Standard File
  1708. static pascal Boolean SaveDialogFilter(DialogPtr theDialog, EventRecord *theEvent,
  1709.                                       short *itemHit, void *myDataPtr)
  1710. {
  1711.     #pragma unused(myDataPtr)
  1712.  
  1713.     if (StdFilterProc(theDialog, theEvent, itemHit))
  1714.         return true;
  1715.  
  1716.     // Pass updates through (Activates are tricky...was mucking with Apple menu & thereby
  1717.     // drastically changing how the system handles the menu bar during our alert)
  1718.     if (theEvent->what == updateEvt /* || theEvent->what == activateEvt */ )
  1719.         {
  1720.         HandleEvent(theEvent);
  1721.         }
  1722.  
  1723.     return false;
  1724.  
  1725. } // SaveDialogFilter
  1726.  
  1727. #if GENERATINGCFM
  1728.     static RoutineDescriptor gSaveDialogFilterRD = BUILD_ROUTINE_DESCRIPTOR(uppModalFilterYDProcInfo, SaveDialogFilter);
  1729.     static ModalFilterYDUPP gSaveDialogFilter = &gSaveDialogFilterRD;
  1730. #else
  1731.     static ModalFilterYDUPP gSaveDialogFilter = NewModalFilterYDProc(SaveDialogFilter);
  1732. #endif
  1733.  
  1734. // --------------------------------------------------------------------------------------------------------------
  1735. #define kLoadAnnotations    true
  1736. #define kSaveAnnotations    false
  1737.  
  1738. static OSErr    LoadOrSaveAnnotations(WindowDataPtr pData, Boolean load)
  1739. {
  1740.     OSErr                anErr = noErr;
  1741.     short                i;
  1742.     short                oldResFile = CurResFile();
  1743.     userSpool             block;
  1744.     
  1745.     block.spool.spoolProcedure = gHandleSpoolProc;
  1746.     
  1747.     UseResFile(((GXDataPtr)pData)->printFileRefNum);
  1748.     for (i = 0; i < ((GXDataPtr)pData)->numberOfPages; ++i)
  1749.         {
  1750.         gxShape annotation = (*((GXDataPtr)pData)->pageAnnotations)[i];
  1751.         Handle    annotationHandle;
  1752.         
  1753.         block.spool.buffer = nil;
  1754.         block.spool.bufferSize = 0;
  1755.         if (load)
  1756.             {
  1757.             // load annotation, if any
  1758.             annotationHandle = Get1Resource(kAnnotationType, kAnnotationBaseID + i-1);
  1759.             if (annotationHandle)
  1760.                 {
  1761.                 block.data = annotationHandle;
  1762.                 annotation = GXUnflattenShape(&block.spool, 0, nil);
  1763.                 ReleaseResource(annotationHandle);
  1764.                 }
  1765.             else
  1766.                 {
  1767.                 annotation = nil;
  1768.                 }
  1769.             }
  1770.         else
  1771.             {
  1772.             // remove old annotation
  1773.             annotationHandle = Get1Resource(kAnnotationType, kAnnotationBaseID + i-1);
  1774.             if (annotationHandle)
  1775.                 RemoveResource(annotationHandle);
  1776.                 
  1777.             // add new annotation
  1778.             if (annotation)
  1779.                 {
  1780.                 block.spool.spoolProcedure = gHandleSpoolProc;
  1781.                 block.spool.buffer = nil;
  1782.                 block.spool.bufferSize = 0;
  1783.                 GXFlattenShape(annotation, 0, &block.spool);
  1784.                 annotationHandle = (Handle) block.data;
  1785.                 if (annotationHandle)
  1786.                     {
  1787.                     AddResource(annotationHandle, kAnnotationType, kAnnotationBaseID + i-1, "\p");
  1788.                     ReleaseResource(annotationHandle);
  1789.                     }
  1790.                 }
  1791.             }
  1792.             
  1793.         (*((GXDataPtr)pData)->pageAnnotations)[i] = annotation;
  1794.         }
  1795.     UpdateResFile(CurResFile());
  1796.     UseResFile(oldResFile);
  1797.     
  1798.     return(anErr);
  1799.     
  1800. } // LoadOrSaveAnnotations
  1801.  
  1802. // --------------------------------------------------------------------------------------------------------------
  1803. static OSErr    GXSaveAs(WindowRef pWindow, WindowDataPtr pData)
  1804. {
  1805.     OSErr                anErr = noErr;
  1806.     Boolean                replacing;
  1807.     FSSpec                fileSpec;
  1808.     NavReplyRecord        navReply;
  1809.     
  1810.     
  1811.     // ask where and how to save this document
  1812.     {
  1813.     Str255    defaultName;
  1814.     Point    where = {-1, -1};
  1815.     
  1816.     // setup for the call
  1817.     GetWTitle(pWindow, defaultName);
  1818.     SetCursor(&qd.arrow);
  1819.     
  1820.     // find out where the user wants the file
  1821.     if (gMachineInfo.haveNavigationServices)
  1822.     {        
  1823.         anErr = SaveFileDialog(defaultName, pData->originalFileType, 'ttxt', MyEventProc, &fileSpec, NULL, &replacing, &navReply);
  1824.         if ( anErr == userCanceledErr)
  1825.             anErr = eUserCanceled;
  1826.     }
  1827.     else
  1828.     {
  1829.         StandardFileReply    sfReply;
  1830.         
  1831.         CustomPutFile("\p", defaultName, &sfReply, 
  1832.                     sfPutDialogID, where,
  1833.                     nil, gSaveDialogFilter, nil, nil, nil);
  1834.  
  1835.         // map the cancel button into a cancelling error
  1836.         if (!sfReply.sfGood)
  1837.             anErr = eUserCanceled;
  1838.             
  1839.         replacing    = sfReply.sfReplacing;
  1840.         fileSpec    = sfReply.sfFile;
  1841.     }
  1842.     
  1843.     }
  1844.         
  1845.     // can't replace over other types    
  1846.     if (replacing)
  1847.         {
  1848.         FInfo    theInfo;
  1849.         
  1850.         FSpGetFInfo(&fileSpec, &theInfo);
  1851.         
  1852.         if ( 
  1853.             (theInfo.fdType != 'sjob') && 
  1854.             (theInfo.fdType != 'tjob') && 
  1855.             (theInfo.fdType != 'rjob') && 
  1856.             (theInfo.fdType != 'qjob') 
  1857.             )
  1858.             anErr = eDocumentWrongKind;
  1859.         }
  1860.     nrequire(anErr, StandardPutFile);
  1861.         
  1862.     GXSavePrintFile(((GXDataPtr)pData)->thePrintFile, &fileSpec);
  1863.     anErr = GXGetJobError(pData->hPrint);
  1864.  
  1865.  
  1866.     // FALL THROUGH EXCEPTION HANDLING
  1867. StandardPutFile:
  1868.  
  1869.     // if everything went okay
  1870.     if (anErr == noErr)
  1871.         {
  1872.         // update the window title 
  1873.         SetWTitle(pWindow, fileSpec.name);
  1874.     
  1875.         // save new location
  1876.         BlockMoveData(&fileSpec, &pData->fileSpec, sizeof(FSSpec));
  1877.  
  1878.         // update the refNum
  1879.         ((GXDataPtr)pData)->printFileRefNum = CurResFile();
  1880.         
  1881.         // and read in the current page
  1882.         anErr = GetCurrentPage((GXDataPtr) pData, true);
  1883.         }
  1884.         
  1885.     if (gMachineInfo.haveNavigationServices)
  1886.     {
  1887.         CompleteSave(&fileSpec, &navReply);
  1888.     }
  1889.     
  1890.     return anErr;
  1891.     
  1892. } // GXSaveAs
  1893.  
  1894. // --------------------------------------------------------------------------------------------------------------
  1895. // OOP INTERFACE ROUTINES
  1896. // --------------------------------------------------------------------------------------------------------------
  1897.  
  1898. static OSErr    GXCloseWindow(WindowRef pWindow, WindowDataPtr pData)
  1899. {
  1900. #pragma unused (pWindow)
  1901.  
  1902.     if (((GXDataPtr)pData)->pageAnnotations)
  1903.         {
  1904.         short    i;
  1905.         
  1906.         for (i = 0; i < ((GXDataPtr)pData)->numberOfPages; ++i)
  1907.             {
  1908.             gxShape annotation = (*((GXDataPtr)pData)->pageAnnotations)[i];
  1909.             
  1910.             if (annotation)
  1911.                 GXDisposeShape(annotation);
  1912.             }
  1913.         DisposeHandle((Handle) (((GXDataPtr)pData)->pageAnnotations) );
  1914.         ((GXDataPtr)pData)->pageAnnotations = nil;
  1915.         }
  1916.     
  1917.     if (((GXDataPtr)pData)->currentSelectionShape)
  1918.         {
  1919.         GXDisposeShape(((GXDataPtr)pData)->currentSelectionShape);
  1920.         ((GXDataPtr)pData)->currentSelectionShape = nil;
  1921.         }
  1922.                         
  1923.     if (((GXDataPtr)pData)->currentPageShape)
  1924.         {
  1925.         GXDisposeShape(((GXDataPtr)pData)->currentPageShape);
  1926.         ((GXDataPtr)pData)->currentPageShape = nil;
  1927.         }
  1928.     GXClosePrintFile( ((GXDataPtr)pData)->thePrintFile);
  1929.  
  1930.     GXDisposeViewPort( ((GXDataPtr)pData)->parentViewPort);
  1931.     GXDisposeViewPort( ((GXDataPtr)pData)->childViewPort);
  1932.  
  1933.     return(noErr);
  1934.     
  1935. } // GXCloseWindow
  1936.  
  1937. // --------------------------------------------------------------------------------------------------------------
  1938.  
  1939. static OSErr    GXUpdateWindow(WindowRef pWindow, WindowDataPtr pData)
  1940. {
  1941.     gxGraphicsError        anErr = noErr;    
  1942.  
  1943.     // draw informational area to the left of the horizontal scroll bar
  1944.     {
  1945.     FontInfo    theInfo;
  1946.     Rect        infoArea;
  1947.     RgnHandle    oldClip = NewRgn();
  1948.     Handle        theString;
  1949.     long        theStringSize;
  1950.     
  1951.     // save old clip and clip to the label area
  1952.     GetClip(oldClip);
  1953.     infoArea.left = 0;
  1954.     infoArea.right = pData->hScrollOffset-1;
  1955.     infoArea.bottom = GetWindowPort(pWindow)->portRect.bottom;
  1956.     infoArea.top = infoArea.bottom - kScrollBarSize;
  1957.     ClipRect(&infoArea);
  1958.         
  1959.     // draw the label
  1960.     TextFont(applFont);
  1961.     TextSize(9);
  1962.     GetFontInfo(&theInfo);
  1963.     theString = GetResource('LSTR', kLabelString);
  1964.     if (theString)
  1965.         {
  1966.         Handle    inString = NewHandle(sizeof(Str255));
  1967.         Str255    newString;
  1968.         Rect    labelArea = infoArea;
  1969.         
  1970.         // erase any old string we had there
  1971.         labelArea.right -= kZoomControlsWidth + kToolControlWidth;
  1972.         if (((GXDataPtr)pData)->numberOfPages > 1)
  1973.             labelArea.left += kPageControlsWidth;        
  1974.         EraseRect(&labelArea);
  1975.         
  1976.         // current page label
  1977.         NumToString(((GXDataPtr)pData)->currentPage, newString);
  1978.         SetHandleSize(inString, newString[0]);
  1979.         BlockMoveData(&newString[1], *inString, newString[0]);
  1980.         ReplaceText(theString, inString, "\p^0");
  1981.  
  1982.         // total page count label
  1983.         NumToString(((GXDataPtr)pData)->numberOfPages, newString);
  1984.         SetHandleSize(inString, newString[0]);
  1985.         BlockMoveData(&newString[1], *inString, newString[0]);
  1986.         ReplaceText(theString, inString, "\p^1");
  1987.  
  1988.         // scale factor label
  1989.         NumToString(FixedToInt( FixedMultiply(((GXDataPtr)pData)->zoomFactor, ff(100)) ), newString);
  1990.         SetHandleSize(inString, newString[0]);
  1991.         BlockMoveData(&newString[1], *inString, newString[0]);
  1992.         ReplaceText(theString, inString, "\p^2");
  1993.  
  1994.         // done with replace string content
  1995.         DisposeHandle(inString);
  1996.         
  1997.         // draw the label
  1998.         HLock(theString);
  1999.         theStringSize = GetHandleSize(theString);
  2000.         MoveTo(labelArea.left + ((labelArea.right - labelArea.left) >> 1) - (TextWidth(*theString, 0, theStringSize) >> 1), 
  2001.                 labelArea.top + ((labelArea.bottom - labelArea.top)>>1) + ((theInfo.ascent + theInfo.descent) >> 1) - theInfo.descent);
  2002.         DrawText(*theString, 0, theStringSize);
  2003.         ReleaseResource(theString);
  2004.         }
  2005.         
  2006.     // draw the current tool
  2007.         {
  2008.         Rect        toolArea = infoArea;
  2009.         CIconHandle    icon;
  2010.         
  2011.         toolArea.left = toolArea.right - kToolControlWidth;
  2012.         toolArea.right = toolArea.left + 32;
  2013.         toolArea.bottom = toolArea.top + 32;
  2014.         EraseRect(&toolArea);
  2015.         OffsetRect(&toolArea, -8, -8);
  2016.         
  2017.         icon = GetCIcon(kIconBase + ((GXDataPtr)pData)->contentClickMode);
  2018.         if (icon)
  2019.             {
  2020.             PlotCIconHandle(&toolArea, kAlignAbsoluteCenter, ttNone, icon);
  2021.             DisposeCIcon(icon);
  2022.             }
  2023.         }
  2024.  
  2025.     // draw the zoom controls
  2026.         {
  2027.         Rect    zoomArea = infoArea;
  2028.         zoomArea.left = zoomArea.right - kZoomControlsWidth - kToolControlWidth;
  2029.         zoomArea.right = zoomArea.left + 32;
  2030.         zoomArea.bottom = zoomArea.top + 32;
  2031.         
  2032.         PlotIconID(&zoomArea, ttNone, ttNone, kZoomControlPlain);
  2033.         }
  2034.                 
  2035.     // draw the left/right/page arrows
  2036.     if (((GXDataPtr)pData)->numberOfPages > 1)
  2037.         {
  2038.         Rect    arrowsRect;
  2039.         
  2040.         // erase any old arrow bits, including around the edges of the icon
  2041.         // needed when the window resizes
  2042.         arrowsRect = infoArea;
  2043.         arrowsRect.bottom = arrowsRect.top + 32;
  2044.         arrowsRect.right = arrowsRect.left + 34;
  2045.         EraseRect(&arrowsRect);
  2046.         
  2047.         // then draw the new arrows
  2048.         arrowsRect.left = infoArea.left + 2;
  2049.         arrowsRect.top = infoArea.top + 2;
  2050.         arrowsRect.right = arrowsRect.left + kPageControlsWidth;
  2051.         arrowsRect.bottom = arrowsRect.top + 32;
  2052.         PlotIconID(&arrowsRect, ttNone, ttNone, kPageControlPlain);
  2053.         }
  2054.     
  2055.     // frame the area
  2056.     MoveTo(infoArea.left, infoArea.top);
  2057.     LineTo(infoArea.right, infoArea.top);
  2058.  
  2059.     // restore old clip value
  2060.     SetClip(oldClip);
  2061.     DisposeRgn(oldClip);
  2062.     }
  2063.  
  2064.  
  2065.     // then draw the page shape and things around it
  2066.     {
  2067.     gxRectangle            pageSize, paperSize;    
  2068.     gxShape                tempShape, pageShape;
  2069.     gxMapping            thisMapping;
  2070.  
  2071.     // clip to the content area
  2072.     paperSize.left         = ff(pData->contentRect.left);
  2073.     paperSize.top         = ff(pData->contentRect.top);
  2074.     paperSize.right     = ff(pData->contentRect.right);
  2075.     paperSize.bottom     = ff(pData->contentRect.bottom);
  2076.     tempShape = GXNewRectangle(&paperSize);
  2077.     GXSetViewPortClip(((GXDataPtr)pData)->childViewPort, tempShape);
  2078.     GXDisposeShape(tempShape);
  2079.     
  2080.     // get the paper sizes, account for zoom factor
  2081.     GetCurrentPageAndPaper(pData, &pageSize, &paperSize);
  2082.     pageSize.left         = FixedMultiply(pageSize.left, ((GXDataPtr)pData)->zoomFactor);
  2083.     pageSize.right         = FixedMultiply(pageSize.right, ((GXDataPtr)pData)->zoomFactor);
  2084.     pageSize.top         = FixedMultiply(pageSize.top, ((GXDataPtr)pData)->zoomFactor);
  2085.     pageSize.bottom     = FixedMultiply(pageSize.bottom, ((GXDataPtr)pData)->zoomFactor);
  2086.     paperSize.left         = FixedMultiply(paperSize.left, ((GXDataPtr)pData)->zoomFactor);
  2087.     paperSize.right     = FixedMultiply(paperSize.right, ((GXDataPtr)pData)->zoomFactor);
  2088.     paperSize.top         = FixedMultiply(paperSize.top, ((GXDataPtr)pData)->zoomFactor);
  2089.     paperSize.bottom     = FixedMultiply(paperSize.bottom, ((GXDataPtr)pData)->zoomFactor);
  2090.     
  2091.     // offset by the scrolling amount    
  2092.     ResetMapping(&thisMapping);
  2093.     MoveMapping(&thisMapping, Long2Fix(-GetControlValue(pData->hScroll)) - paperSize.left ,
  2094.                 Long2Fix(-GetControlValue(pData->vScroll)) - paperSize.top );
  2095.  
  2096.     // make the paper shape
  2097.     tempShape = GXNewShape(gxFullType);
  2098.     GXSetTransformViewPorts(GXGetShapeTransform(tempShape), 1, & ((GXDataPtr)pData)->childViewPort);
  2099.     GXSetShapeFill(tempShape, gxEvenOddFill);
  2100.     GXSetShapeMapping(tempShape, &thisMapping);
  2101.     
  2102.     // make the page shape
  2103.     pageShape = GXNewRectangle(&pageSize);
  2104.     GXSetTransformViewPorts(GXGetShapeTransform(pageShape), 1, & ((GXDataPtr)pData)->childViewPort);
  2105.     GXSetShapeFill(pageShape, gxEvenOddFill);
  2106.     GXSetShapeMapping(pageShape, &thisMapping);
  2107.     
  2108.     // remove the page shape from the paper shape
  2109.     GXDifferenceShape(tempShape, pageShape);
  2110.  
  2111.     // draw the paper shape, dispose of it
  2112.     SetShapeGreyColorLevel(tempShape, 0xD000);    /* Set up light gray background */
  2113.     GXDrawShape(tempShape);
  2114.     GXDisposeShape(tempShape);
  2115.     
  2116.     // draw white on the page shape
  2117.     SetShapeGreyColorLevel(pageShape, 0xFFFF);    /* Set up white page */
  2118.     GXSetShapeFill(pageShape, gxEvenOddFill);
  2119.     GXDrawShape(pageShape);
  2120.     
  2121.     // frame the page shape
  2122.     SetShapeGreyColorLevel(pageShape, 0x8000);    /* Set up medium gray frame */
  2123.     GXSetShapeFill(pageShape, gxClosedFrameFill);
  2124.     GXDrawShape(pageShape);
  2125.     
  2126.     // draw the scroll bars and grow box now to give a nice appearence
  2127.     DrawControls(pWindow);
  2128.     DrawGrowIcon(pWindow);
  2129.  
  2130.     // draw the page data itself, clipped to the page
  2131.  
  2132.     {
  2133.     gxMapping    oldMapping, flipMapping;
  2134.     
  2135.     // get the page shape's old mapping, and make a copy to work with
  2136.     GXGetShapeMapping(((GXDataPtr)pData)->currentPageShape, &oldMapping);
  2137.  
  2138.     // run the clip through the inverse of the shape mapping to scale it properly
  2139.     GXInsetShape(pageShape, ff(1));
  2140.     ScaleMapping(&oldMapping, ((GXDataPtr)pData)->zoomFactor, ((GXDataPtr)pData)->zoomFactor, 0, 0);
  2141.     InvertMapping(&flipMapping, &oldMapping);
  2142.     GXMapShape(pageShape, &flipMapping);
  2143.     GXSetShapeFill(pageShape, gxEvenOddFill);
  2144.     GXSetShapeClip( ((GXDataPtr)pData)->currentPageShape, pageShape);
  2145.     
  2146.     // move the shape into position by offseting the viewPort
  2147.     GXGetViewPortMapping(((GXDataPtr)pData)->childViewPort, &thisMapping);    
  2148.     GXGetViewPortMapping(((GXDataPtr)pData)->childViewPort, &oldMapping);    
  2149.     ScaleMapping(&thisMapping, ((GXDataPtr)pData)->zoomFactor, ((GXDataPtr)pData)->zoomFactor, 0, 0);
  2150.     MoveMapping(&thisMapping, Long2Fix(-GetControlValue(pData->hScroll)) - paperSize.left ,
  2151.                 Long2Fix(-GetControlValue(pData->vScroll)) - paperSize.top );
  2152.     GXSetViewPortMapping(((GXDataPtr)pData)->childViewPort, &thisMapping);    
  2153.  
  2154.     /*
  2155.      *    Bracket the call to DrawShape with UseResFile, so that we put the
  2156.      *    document's resfile on top, allowing the translator (for QDShapes)
  2157.      *    to see our embedded fonts (if any) first.
  2158.      */
  2159.     {    short oldResFile = CurResFile();
  2160.     
  2161.         UseResFile(((GXDataPtr)pData)->printFileRefNum);
  2162.         GXDrawShape( ((GXDataPtr)pData)->currentPageShape);
  2163.         UseResFile(oldResFile);
  2164.     }
  2165.  
  2166.     
  2167.     // Draw the selection, if any
  2168.     {
  2169.     gxShape    selectionShape =  ((GXDataPtr)pData)->currentSelectionShape;
  2170.     gxShape    highlight;
  2171.     
  2172.     if (selectionShape)
  2173.         {
  2174.         
  2175.         // better be a layout shape to get hilights
  2176.         GXSetShapeType(selectionShape, gxLayoutType);
  2177.         
  2178.         // get the highlight
  2179.         highlight = GetCurrentSelectionHighlight(pData, true);
  2180.         GXDrawShape(highlight);
  2181.         GXDisposeShape(highlight);                        
  2182.         }
  2183.     }
  2184.  
  2185.     // Draw the overlay, if any
  2186.     {
  2187.     gxShape    annotationShape =  (*((GXDataPtr)pData)->pageAnnotations)[((GXDataPtr)pData)->currentPage-1];
  2188.     
  2189.     if (annotationShape)
  2190.         {
  2191.         GXSetShapeViewPorts(annotationShape, 1, &((GXDataPtr)pData)->childViewPort);
  2192.         GXDrawShape(annotationShape);
  2193.         }    
  2194.     }
  2195.  
  2196.     // restore viewPort's mapping (so we don't use it again next time)
  2197.     GXSetViewPortMapping(((GXDataPtr)pData)->childViewPort, &oldMapping);    
  2198.  
  2199.     
  2200.     }
  2201.     
  2202.     // done with the page shape
  2203.     GXDisposeShape(pageShape);
  2204.  
  2205.     DrawSelection(pData, &((GXDataPtr)pData)->selectionRectangle, &((GXDataPtr)pData)->patternPhase, false);
  2206.  
  2207.     GXGetGraphicsError(&anErr);
  2208.     }
  2209.     
  2210.     return(anErr);
  2211.     
  2212. } // GXUpdateWindow
  2213.  
  2214. // --------------------------------------------------------------------------------------------------------------
  2215.  
  2216. static OSErr    GXContentClick(WindowRef pWindow, WindowDataPtr pData, EventRecord *pEvent)
  2217. {
  2218.     OSErr            anErr = noErr;
  2219.     Point            clickPoint = pEvent->where;
  2220.     Rect            infoArea, labelArea, toolArea;
  2221.     Rect            zoomOutRect, zoomInRect, zoomsRect;
  2222.     RgnHandle        oldClip = NewRgn();
  2223.     Boolean            somethingHit = false;
  2224.     
  2225.     // convert to local space, calculate clickable areas    
  2226.     GlobalToLocal(&clickPoint);
  2227.     infoArea.left = 0;
  2228.     infoArea.right = pData->hScrollOffset-1;
  2229.     infoArea.bottom = GetWindowPort(pWindow)->portRect.bottom;
  2230.     infoArea.top = infoArea.bottom - kScrollBarSize;
  2231.  
  2232.     // clip to the info area
  2233.     GetClip(oldClip);
  2234.     ClipRect(&infoArea);
  2235.  
  2236.     // label area
  2237.     labelArea = infoArea;
  2238.     labelArea.right -= kZoomControlsWidth + kToolControlWidth;
  2239.     if (((GXDataPtr)pData)->numberOfPages > 1)
  2240.         labelArea.left += kPageControlsWidth;        
  2241.  
  2242.     // the tool pop up
  2243.     toolArea = infoArea;
  2244.     toolArea.left = toolArea.right - kToolControlWidth;
  2245.     
  2246.     // calculate the zoom in/out rects
  2247.     zoomInRect = infoArea;
  2248.     zoomInRect.right -= kToolControlWidth;
  2249.     zoomInRect.left = zoomInRect.right - 13;
  2250.     zoomOutRect = zoomInRect;
  2251.     OffsetRect(&zoomOutRect, -13, 0);
  2252.     zoomsRect = zoomOutRect;
  2253.     zoomsRect.bottom = zoomsRect.top + 32;
  2254.     zoomsRect.right = zoomsRect.left + 32;
  2255.  
  2256.     // deal with zoom in/out clicks
  2257.     if (TrackIn(&zoomInRect, clickPoint, &zoomsRect, kZoomControlRight, kZoomControlPlain))
  2258.         {
  2259.         somethingHit = true;
  2260.         SetZoom(pWindow, pData, FixedMultiply(((GXDataPtr)pData)->zoomFactor, ff(2)) );
  2261.         PlotIconID(&zoomsRect, ttNone, ttNone, kZoomControlPlain);
  2262.         }
  2263.  
  2264.     if (TrackIn(&zoomOutRect, clickPoint, &zoomsRect, kZoomControlLeft, kZoomControlPlain))
  2265.         {
  2266.         somethingHit = true;
  2267.         SetZoom(pWindow, pData, FixedDivide(((GXDataPtr)pData)->zoomFactor, ff(2)) );
  2268.         PlotIconID(&zoomsRect, ttNone, ttNone, kZoomControlPlain);
  2269.         }
  2270.  
  2271.     // deal with the options pop up
  2272.     if (PtInRect(clickPoint, &labelArea))
  2273.         {
  2274.         MenuHandle    popupMenu = GetMenu(kGXPopUpMenu);
  2275.         short        selectedItem;
  2276.         TextState    textState;
  2277.         Point        popPoint;
  2278.         char        bulletString[3];
  2279.         
  2280.         // figure out where to display the pop up
  2281.         popPoint.v = labelArea.top;
  2282.         popPoint.h = labelArea.left;
  2283.         LocalToGlobal(&popPoint);
  2284.  
  2285.         somethingHit = true;
  2286.         GetIntlTokenChar(tokenCenterDot, FontToScript(applFont), bulletString);
  2287.         
  2288.         // set up menu to be small sized
  2289.         TextFont(applFont);
  2290.         TextSize(9);
  2291.         DoUseWFont(&textState, pWindow, true);
  2292.         
  2293.         // set up the menu for selected items
  2294.         SetItemMark(popupMenu, iDontShowMargins, (((GXDataPtr)pData)->dontShowMargins) ? bulletString[1] : noMark);
  2295.         {
  2296.         ZoomTableEntry *pEntry = &gZoomTable[0];
  2297.         
  2298.         while (pEntry->menuItem != 0)
  2299.             {
  2300.             SetItemMark(popupMenu, pEntry->menuItem, (((GXDataPtr)pData)->zoomFactor == pEntry->zoomFactor) ? bulletString[1] : noMark);
  2301.             pEntry++;
  2302.             }
  2303.         }
  2304.         
  2305.         // conduct the menu
  2306.         InsertMenu(popupMenu, -1);
  2307.         selectedItem = PopUpMenuSelect(popupMenu, popPoint.v, popPoint.h, CountMItems(popupMenu)+1) & 0xFFFF;
  2308.  
  2309.         // restore menu sizes
  2310.         DoUseWFont(&textState, nil, false);
  2311.         DeleteMenu(kGXPopUpMenu);
  2312.         
  2313.         switch (selectedItem)
  2314.             {                
  2315.             // toggle show/hide margins
  2316.             case iDontShowMargins:
  2317.                 // flip the boolean
  2318.                 ((GXDataPtr)pData)->dontShowMargins = 1 - ((GXDataPtr)pData)->dontShowMargins;
  2319.                 
  2320.                 // force update and recalc the size of window
  2321.                 InvalRect(&GetWindowPort(pWindow)->portRect);
  2322.                 AdjustScrollBars(pWindow, true, true, nil);
  2323.                 break;
  2324.  
  2325.             // scale graphics to fit the window
  2326.             case iScaleToFit:
  2327.                 {
  2328.                 gxRectangle        pageSize, paperSize;
  2329.                 Fixed            horizScale, vertScale;
  2330.                 GrafPtr            pPort = (GrafPtr)GetWindowPort(pWindow);
  2331.                 
  2332.                 GetCurrentPageAndPaper(pData, &pageSize, &paperSize);
  2333.                 
  2334.                 pageSize.left = pageSize.top = 0;
  2335.                 pageSize.right = ff(pPort->portRect.right - kScrollBarSize);
  2336.                 pageSize.bottom = ff(pPort->portRect.bottom - kScrollBarSize);
  2337.                 
  2338.                 horizScale = FixedDivide(pageSize.right - pageSize.left, paperSize.right - paperSize.left);
  2339.                 vertScale = FixedDivide(pageSize.bottom - pageSize.top, paperSize.bottom - paperSize.top);
  2340.                 if (horizScale > vertScale)
  2341.                     SetZoom(pWindow, pData, vertScale);
  2342.                 else
  2343.                     SetZoom(pWindow, pData, horizScale);
  2344.                 }
  2345.                 break;
  2346.                 
  2347.             // absolute set scale cases
  2348.             default:
  2349.                 {
  2350.                 ZoomTableEntry *pEntry = &gZoomTable[0];
  2351.                 
  2352.                 while (pEntry->menuItem != 0)
  2353.                     {
  2354.                     if (selectedItem == pEntry->menuItem)
  2355.                         SetZoom(pWindow, pData, pEntry->zoomFactor);
  2356.                     pEntry++;
  2357.                     }
  2358.                 }
  2359.                 break;
  2360.             }
  2361.             
  2362.         }
  2363.         
  2364.     // deal with the tool pop up
  2365.     if (PtInRect(clickPoint, &toolArea))
  2366.         {
  2367.         MenuHandle    popupMenu = GetMenu(kGXToolMenu);
  2368.         short        selectedItem;
  2369.         Point        popPoint;
  2370.         short        i, numItems;
  2371.         
  2372.         // figure out where to display the pop up
  2373.         popPoint.v = toolArea.top;
  2374.         popPoint.h = toolArea.left;
  2375.         LocalToGlobal(&popPoint);
  2376.  
  2377.         // we've processed the mouse click
  2378.         somethingHit = true;
  2379.         
  2380.         // select our current item in the menu
  2381.         numItems = CountMItems(popupMenu);
  2382.         for (i = 1; i <= numItems; ++i)
  2383.             CheckItem(popupMenu, i, (i == ((GXDataPtr)pData)->contentClickMode) );
  2384.         
  2385.         // conduct the menu
  2386.         InsertMenu(popupMenu, -1);
  2387.         selectedItem = PopUpMenuSelect(popupMenu, popPoint.v, popPoint.h, numItems+1) & 0xFFFF;
  2388.         DeleteMenu(kGXPopUpMenu);
  2389.  
  2390.         // remember the item selected
  2391.         if (selectedItem != 0)
  2392.             ((GXDataPtr)pData)->contentClickMode = selectedItem;
  2393.             
  2394.         // invalidation the tool picture
  2395.         InvalRect(&toolArea);
  2396.         
  2397.         if (selectedItem != kSelectionTool)
  2398.             {
  2399.             // erase the old selection
  2400.             DrawSelection(pData, &((GXDataPtr)pData)->selectionRectangle, &((GXDataPtr)pData)->patternPhase, false);
  2401.     
  2402.             // clear the selection
  2403.             ((GXDataPtr)pData)->selectionRectangle.top         = 0;
  2404.             ((GXDataPtr)pData)->selectionRectangle.left        = 0;
  2405.             ((GXDataPtr)pData)->selectionRectangle.bottom    = 0;
  2406.             ((GXDataPtr)pData)->selectionRectangle.right    = 0;
  2407.     
  2408.             // draw the new selection
  2409.             DrawSelection(pData, &((GXDataPtr)pData)->selectionRectangle, &((GXDataPtr)pData)->patternPhase, true);
  2410.             }
  2411.         }
  2412.         
  2413.     // deal with clicks in page controls
  2414.     if (((GXDataPtr)pData)->numberOfPages > 1)
  2415.         {
  2416.         Rect    leftArrowRect, rightArrowRect, arrowsRect;
  2417.         Rect    gotoPageRect;
  2418.         
  2419.         // calculate the minus one page arrow        
  2420.         leftArrowRect.top         = infoArea.top + 2;
  2421.         leftArrowRect.bottom     = leftArrowRect.top + 32;
  2422.         leftArrowRect.left         = infoArea.left + 2;
  2423.         leftArrowRect.right     = leftArrowRect.left + 11;
  2424.                 
  2425.         // calculate the go to a particular page rect        
  2426.         gotoPageRect = leftArrowRect;
  2427.         OffsetRect(&gotoPageRect, 11, 0);
  2428.         gotoPageRect.right --;
  2429.  
  2430.         // calculate the plus one page arrow        
  2431.         rightArrowRect = gotoPageRect;
  2432.         OffsetRect(&rightArrowRect, 10, 0);
  2433.         
  2434.         // calculate sum of all areas
  2435.         arrowsRect = leftArrowRect;
  2436.         arrowsRect.left     = infoArea.left + 2;
  2437.         arrowsRect.right     = arrowsRect.left + kPageControlsWidth;
  2438.                     
  2439.         if (TrackIn(&leftArrowRect, clickPoint, &arrowsRect, kPageControlLeft, kPageControlPlain))
  2440.             {
  2441.             somethingHit = true;
  2442.             if (((GXDataPtr)pData)->currentPage > 1) 
  2443.                 anErr = GXCommand(pWindow, pData, cPreviousPage, 0);
  2444.             else
  2445.                 PlotIconID(&arrowsRect, ttNone, ttNone, kPageControlPlain);
  2446.             }
  2447.  
  2448.         if (TrackIn(&rightArrowRect, clickPoint, &arrowsRect, kPageControlRight, kPageControlPlain))
  2449.             {
  2450.             somethingHit = true;
  2451.             if (((GXDataPtr)pData)->currentPage < ((GXDataPtr)pData)->numberOfPages)
  2452.                 anErr = GXCommand(pWindow, pData, cNextPage, 0);
  2453.             else
  2454.                 PlotIconID(&arrowsRect, ttNone, ttNone, kPageControlPlain);
  2455.             }
  2456.             
  2457.         if (PtInRect(clickPoint, &gotoPageRect))
  2458.             {
  2459.             long    actualTicks;
  2460.             
  2461.             somethingHit = true;
  2462.             // pause, then check if the mouse is still down
  2463.             Delay(20, &actualTicks);
  2464.             
  2465.             // if still down, track preview window
  2466.             if (StillDown())
  2467.                 {
  2468.                 WindowRef    popWindow;
  2469.                 Rect        windowRect;
  2470.                 short        oldResFile = CurResFile();
  2471.                 
  2472.                 // put the print file on top
  2473.                 UseResFile(((GXDataPtr)pData)->printFileRefNum);
  2474.                 
  2475.                 // figure out where to place the pop up window, and then make it
  2476.                 windowRect.bottom     = arrowsRect.top - 2;
  2477.                 windowRect.left        = 2;
  2478.                 if (Count1Resources(kProxyType) > 0)
  2479.                     windowRect.top = windowRect.bottom - kPopUpWindowHeightLarge;
  2480.                 else
  2481.                     windowRect.top = windowRect.bottom - kPopUpWindowHeightSmall;
  2482.                 windowRect.right     = windowRect.left + kScrollAreaWidth + kPageControlsWidth + kZoomControlsWidth + kToolControlWidth - 4;
  2483.                     
  2484.                 LocalToGlobal(&TopLeft(windowRect));                
  2485.                 LocalToGlobal(&BotRight(windowRect));                
  2486.                 
  2487.                 popWindow = (WindowRef) NewCWindow(nil, &windowRect, "\p", true, plainDBox, (WindowPtr)-1, false, 0);
  2488.                 if (popWindow)
  2489.                     {            
  2490.                     long    oldValue = ((GXDataPtr)pData)->currentPage;
  2491.                     long    newValue = oldValue;
  2492.                     GrafPtr    popPort = (GrafPtr)GetWindowPort(popWindow);
  2493.                     
  2494.                     // draw initial location of the value
  2495.                     SetPort(popPort);
  2496.                     DrawPageSliderAndThumb(popWindow, oldValue, ((GXDataPtr)pData)->numberOfPages);
  2497.                                         
  2498.                     // track the mouse, updating the value as we go
  2499.                     while (StillDown())
  2500.                         {
  2501.                         GetMouse(&clickPoint);
  2502.                         if (PtInRect(clickPoint, &popPort->portRect))
  2503.                             {
  2504.                             newValue =     clickPoint.h
  2505.                                             *
  2506.                                         ((GXDataPtr)pData)->numberOfPages
  2507.                                             /
  2508.                                         (popPort->portRect.right - popPort->portRect.left) 
  2509.                                             + 1;
  2510.                                         
  2511.                             if (oldValue != newValue)
  2512.                                 {
  2513.                                 oldValue = newValue;
  2514.                                 DrawPageSliderAndThumb(popWindow, oldValue, ((GXDataPtr)pData)->numberOfPages);
  2515.                                 }
  2516.                             }
  2517.                         }
  2518.                         
  2519.                     // and done with the pop up window, return to main window
  2520.                     DisposeWindow(popWindow);
  2521.                     SetPort((GrafPtr)GetWindowPort(pWindow));
  2522.                     
  2523.                     // if we changed the value, make it so
  2524.                     if (newValue != ((GXDataPtr)pData)->currentPage)
  2525.                         {
  2526.                         ((GXDataPtr)pData)->currentPage = newValue;
  2527.                         anErr = GetCurrentPage((GXDataPtr) pData, true);
  2528.                         InvalRect(&GetWindowPort(pWindow)->portRect);
  2529.                         }
  2530.                     }
  2531.                     
  2532.                 // restore resource chain
  2533.                 UseResFile(oldResFile);
  2534.                 }
  2535.             else
  2536.                 {
  2537.                 // otherwise, do the goto dialog box
  2538.                 anErr = GXCommand(pWindow, pData, cGotoPage, 0);
  2539.                 }
  2540.                 
  2541.             } // if (click in goto page area)
  2542.             
  2543.         } // if (> 1 page)
  2544.  
  2545.     // restore clip
  2546.     SetClip(oldClip);
  2547.     DisposeRgn(oldClip);
  2548.     
  2549.     // nothing matched so far, deal with selecting the contents
  2550.     if (!somethingHit)
  2551.         {
  2552.         Rect    selectionRect = ((GXDataPtr)pData)->selectionRectangle;
  2553.         
  2554.         
  2555.         OffsetRect(&selectionRect, -GetControlValue(pData->hScroll), -GetControlValue(pData->vScroll));
  2556.         if ( (gMachineInfo.haveDragMgr) && (PtInRect(clickPoint, &selectionRect)) )
  2557.             {
  2558.             ((GXDataPtr)pData)->tempDragShape = nil;
  2559.             DragAndDropArea(pWindow, pData, pEvent, 
  2560.                                 &selectionRect);
  2561.                 
  2562.                                 
  2563.             if ( ((GXDataPtr)pData)->tempDragShape )
  2564.                 GXDisposeShape( ((GXDataPtr)pData)->tempDragShape );
  2565.             }
  2566.         else
  2567.             {
  2568.             LongRect        docRect;
  2569.             Rect            contentRect;
  2570.             
  2571.             contentRect = GetWindowPort(pWindow)->portRect;
  2572.             contentRect.right -= kScrollBarSize;
  2573.             contentRect.bottom -= kScrollBarSize;
  2574.             
  2575.             if (PtInRect(clickPoint, &contentRect))
  2576.                 {
  2577.                 switch (((GXDataPtr)pData)->contentClickMode)
  2578.                     {
  2579.                     case kSelectionTool:
  2580.                         GXGetDocumentRect(pWindow, pData, &docRect, false);
  2581.                         contentRect.top     = docRect.top;
  2582.                         contentRect.left     = docRect.left;
  2583.                         contentRect.bottom     = docRect.bottom;
  2584.                         contentRect.right     = docRect.right;
  2585.                         
  2586.                         anErr = SelectContents(pWindow, pData, pEvent, 
  2587.                                             &((GXDataPtr)pData)->selectionRectangle, &contentRect, 
  2588.                                             &((GXDataPtr)pData)->patternPhase);
  2589.                 
  2590.                         // existing text selection? clear the highlight
  2591.                         if (((GXDataPtr)pData)->currentSelectionShape)
  2592.                             {
  2593.                             InvalRect(&GetWindowPort(pWindow)->portRect);
  2594.                             
  2595.                             ClearCurrentSelection((GXDataPtr)pData);
  2596.                             }
  2597.                         break;
  2598.  
  2599.                     case kRedMarkerTool:
  2600.                         DoDrawingClick(pWindow, pData, clickPoint, pEvent);
  2601.                         break;
  2602.                         
  2603.                     } // switch (mode)
  2604.                     
  2605.                 } // click in content rect
  2606.             }
  2607.         }
  2608.         
  2609.     return(anErr);
  2610.         
  2611. } // GXContentClick
  2612.  
  2613. // --------------------------------------------------------------------------------------------------------------
  2614.  
  2615. static OSErr    GXAdjustMenus(WindowRef pWindow, WindowDataPtr pData)
  2616. {
  2617. #pragma unused (pWindow)
  2618.  
  2619.     OSErr anErr = noErr;
  2620.     
  2621.     EnableCommand(cSaveAs);
  2622.  
  2623.     if (((GXDataPtr)pData)->numberOfPages > 1)
  2624.         {
  2625.         if (((GXDataPtr)pData)->currentPage < ((GXDataPtr)pData)->numberOfPages)
  2626.             EnableCommand(cNextPage);
  2627.             
  2628.         if (((GXDataPtr)pData)->currentPage > 1)
  2629.             EnableCommand(cPreviousPage);
  2630.         
  2631.         EnableCommand(cGotoPage);
  2632.         }
  2633.         
  2634.     if (!EmptyRect( &((GXDataPtr)pData)->selectionRectangle) )
  2635.         EnableCommand(cCopy);
  2636.  
  2637.     {
  2638.     LongRect        docRect;
  2639.     Rect            shortDocRect;
  2640.     
  2641.     // find out the size of the document            
  2642.     GXGetDocumentRect(pWindow, pData, &docRect, false);
  2643.     LongRectToRect(&docRect, &shortDocRect);
  2644.     if     (EqualRect(&shortDocRect, &((GXDataPtr)pData)->selectionRectangle))
  2645.         ChangeCommandName(cSelectAll, kMiscStrings, iSelectNoneCommand);
  2646.     else
  2647.         ChangeCommandName(cSelectAll, kMiscStrings, iSelectAllCommand);
  2648.     }
  2649.     EnableCommand(cSelectAll);
  2650.     
  2651.     EnableCommand(cFind);
  2652.     if (gFindString[0] != 0)
  2653.         EnableCommand(cFindAgain);
  2654.     
  2655.     return(anErr);
  2656.     
  2657. } // GXAdjustMenus
  2658.  
  2659. // --------------------------------------------------------------------------------------------------------------
  2660.  
  2661. OSErr    GXCommand(WindowRef pWindow, WindowDataPtr pData, short commandID, long menuResult)
  2662. {
  2663. #pragma unused (menuResult)
  2664.  
  2665.     OSErr    anErr = noErr;
  2666.         
  2667.     switch (commandID)
  2668.         {
  2669.         case cSave:
  2670.             GXSavePrintFile(((GXDataPtr)pData)->thePrintFile, nil);
  2671.             anErr = GXGetJobError(pData->hPrint);
  2672.             if (anErr == noErr)
  2673.                 anErr = LoadOrSaveAnnotations(pData, kSaveAnnotations);
  2674.                 
  2675.             // if everything went okay, then clear the changed bit
  2676.             if (anErr == noErr)
  2677.                 pData->changed = false;
  2678.             break;
  2679.             
  2680.         case cSaveAs:
  2681.             anErr = GXSaveAs(pWindow, pData);
  2682.             if (anErr == noErr)
  2683.                 anErr = LoadOrSaveAnnotations(pData, kSaveAnnotations);
  2684.  
  2685.             // if everything went okay, then clear the changed bit
  2686.             if (anErr == noErr)
  2687.                 pData->changed = false;
  2688.             break;
  2689.             
  2690.         case cFind:
  2691.             if (ConductFindOrReplaceDialog(kFindWindowID) == cancel)    
  2692.                 break;
  2693.             
  2694.             // start search at top of page
  2695.             ((GXDataPtr)pData)->currentShapeIndex = 0;
  2696.             
  2697.         // fall through from find
  2698.         case cFindAgain:
  2699.             {
  2700.             Boolean    isBackwards = ((gEvent.modifiers & shiftKey) != 0);
  2701.             
  2702.             SetWatchCursor();
  2703.  
  2704.             if (!PerformNextFind(pWindow, pData, gFindString, gCaseSensitive, isBackwards, gWrapAround))
  2705.                 SysBeep(1);
  2706.             else
  2707.                 ScrollFoundShapeIntoView(pWindow, pData);
  2708.                 
  2709.             SetCursor(&qd.arrow);
  2710.             }
  2711.             break;
  2712.  
  2713.         case cCopy:
  2714.             {
  2715.             gxShape            cullShape = GetSelectedShape(pData);
  2716.  
  2717.             if (cullShape)
  2718.                 {
  2719.                 // done with the shape now
  2720.                 ShapeToScrap(cullShape);
  2721.                 GXDisposeShape(cullShape);
  2722.                 }
  2723.             }
  2724.             break;
  2725.         
  2726.         case cSelectAll:
  2727.             {
  2728.             LongRect        docRect;
  2729.             Rect            shortDocRect;
  2730.             
  2731.             // find out the size of the document            
  2732.             GXGetDocumentRect(pWindow, pData, &docRect, false);
  2733.  
  2734.             // erase the old selection
  2735.             DrawSelection(pData, &((GXDataPtr)pData)->selectionRectangle, &((GXDataPtr)pData)->patternPhase, false);
  2736.             
  2737.             LongRectToRect(&docRect, &shortDocRect);
  2738.             if     (EqualRect(&shortDocRect, &((GXDataPtr)pData)->selectionRectangle))
  2739.                 {
  2740.                 ((GXDataPtr)pData)->selectionRectangle.top         = 0;
  2741.                 ((GXDataPtr)pData)->selectionRectangle.left        = 0;
  2742.                 ((GXDataPtr)pData)->selectionRectangle.bottom    = 0;
  2743.                 ((GXDataPtr)pData)->selectionRectangle.right    = 0;
  2744.                 }
  2745.             else
  2746.                 {
  2747.                 ((GXDataPtr)pData)->selectionRectangle.top         = docRect.top;
  2748.                 ((GXDataPtr)pData)->selectionRectangle.left        = docRect.left;
  2749.                 ((GXDataPtr)pData)->selectionRectangle.bottom    = docRect.bottom;
  2750.                 ((GXDataPtr)pData)->selectionRectangle.right    = docRect.right;
  2751.                 }
  2752.  
  2753.             // draw the new selection
  2754.             DrawSelection(pData, &((GXDataPtr)pData)->selectionRectangle, &((GXDataPtr)pData)->patternPhase, true);
  2755.             }
  2756.             break;
  2757.  
  2758.         case cPageSetup:
  2759.             DoPageSetup(pWindow);
  2760.             anErr = GetCurrentPage((GXDataPtr) pData, false);
  2761.             InvalRect(&GetWindowPort(pWindow)->portRect);
  2762.             anErr = eActionAlreadyHandled;
  2763.             break;
  2764.             
  2765.         case cNextPage:
  2766.             ((GXDataPtr)pData)->currentPage++;
  2767.             anErr = GetCurrentPage((GXDataPtr) pData, true);
  2768.             InvalRect(&GetWindowPort(pWindow)->portRect);
  2769.             if (anErr == noErr)
  2770.                 anErr = eActionAlreadyHandled;
  2771.             break;
  2772.         
  2773.         case cPreviousPage:
  2774.             ((GXDataPtr)pData)->currentPage--;
  2775.             anErr = GetCurrentPage((GXDataPtr) pData, true);
  2776.             InvalRect(&GetWindowPort(pWindow)->portRect);
  2777.             if (anErr == noErr)
  2778.                 anErr = eActionAlreadyHandled;
  2779.             break;
  2780.         
  2781.         case cGotoPage:
  2782.             switch (menuResult)
  2783.                 {
  2784.                 case cGotoFirst:
  2785.                     ((GXDataPtr)pData)->currentPage = 1;
  2786.                     anErr = GetCurrentPage((GXDataPtr) pData, true);
  2787.                     InvalRect(&GetWindowPort(pWindow)->portRect);
  2788.                     break;
  2789.  
  2790.                 case cGotoLast:
  2791.                     ((GXDataPtr)pData)->currentPage = ((GXDataPtr)pData)->numberOfPages;
  2792.                     anErr = GetCurrentPage((GXDataPtr) pData, true);
  2793.                     InvalRect(&GetWindowPort(pWindow)->portRect);
  2794.                     break;
  2795.                     
  2796.                 default:
  2797.                     {
  2798.                     DialogRef    dPtr;
  2799.                     short        hit;
  2800.                     
  2801.                     dPtr = GetNewDialog(kGotoPageDialogID, nil, (WindowRef)-1);
  2802.                     if (dPtr)
  2803.                         {
  2804.                         short    theType;
  2805.                         Handle    theHandle;
  2806.                         Rect    theRect;
  2807.                         Str255    theString;
  2808.                         
  2809.                         GetDialogItem(dPtr, 4, &theType, &theHandle, &theRect);
  2810.                         NumToString(((GXDataPtr)pData)->currentPage, theString);
  2811.                         SetDialogItemText(theHandle, theString);
  2812.                         SelectDialogItemText(dPtr, 4, 0, 32767);
  2813.  
  2814.                         NumToString(((GXDataPtr)pData)->numberOfPages, theString);
  2815.                         ParamText(theString, "\p", "\p", "\p");
  2816.                         
  2817.                         SetDialogDefaultItem(dPtr, ok);
  2818.                         SetDialogCancelItem(dPtr, cancel);
  2819.                         BeginMovableModal();
  2820.                         
  2821.                         do
  2822.                             {
  2823.                             MovableModalDialog(nil, &hit);
  2824.                             
  2825.                             if (hit == ok)
  2826.                                 {
  2827.                                 long    tempLong;
  2828.                                 
  2829.                                 // convert to a page number, find and report errors
  2830.                                 GetDialogItemText(theHandle, theString);
  2831.                                 StringToNum(theString, &tempLong);
  2832.                                 if (tempLong < 1) 
  2833.                                     {
  2834.                                     SysBeep(1);
  2835.                                     tempLong = 1;
  2836.                                     hit = 0;
  2837.                                     }
  2838.                                 if (tempLong > ((GXDataPtr)pData)->numberOfPages)
  2839.                                     {
  2840.                                     tempLong = ((GXDataPtr)pData)->numberOfPages;
  2841.                                     hit = 0;
  2842.                                     }
  2843.                                     
  2844.                                 // if we have an error, we try again, otherwise we go to the page
  2845.                                 if (hit == 0)
  2846.                                     {
  2847.                                     SysBeep(1);
  2848.                                     NumToString(tempLong, theString);
  2849.                                     SetDialogItemText(theHandle, theString);
  2850.                                     SelectDialogItemText(dPtr, 4, 0, 32767);
  2851.                                     }
  2852.                                 else
  2853.                                     {
  2854.                                     ((GXDataPtr)pData)->currentPage = tempLong;
  2855.                                     anErr = GetCurrentPage((GXDataPtr) pData, true);
  2856.                                     InvalRect(&GetWindowPort(pWindow)->portRect);
  2857.                                     }
  2858.                                 }
  2859.                             } while ((hit != ok) && (hit != cancel));
  2860.                             
  2861.                         DisposeDialog(dPtr);
  2862.                         EndMovableModal();
  2863.                         }
  2864.                         
  2865.                     }
  2866.                     break;
  2867.                     
  2868.                 }
  2869.             if (anErr == noErr)
  2870.                 anErr = eActionAlreadyHandled;
  2871.             break;
  2872.         
  2873.         }
  2874.     
  2875.     return(anErr);
  2876.     
  2877. } // GXCommand
  2878.  
  2879. // --------------------------------------------------------------------------------------------------------------
  2880. static OSErr    GXFilePrintPage(WindowRef pWindow, WindowDataPtr pData,
  2881.                     Rect * pageRect, long *pageNum)
  2882. {
  2883. #pragma unused (pWindow, pageRect)
  2884.  
  2885.     OSErr        anErr = noErr;
  2886.     gxShape     thisShape;
  2887.     gxFormat     thisFormat;
  2888.     
  2889.     GXReadPrintFilePage(((GXDataPtr)pData)->thePrintFile, *pageNum, 0, nil, &thisFormat, &thisShape);
  2890.     anErr = GXGetJobError(pData->hPrint);
  2891.     nrequire(anErr, ReadPrintFilePage);
  2892.  
  2893.     GXPrintPage(pData->hPrint, *pageNum, thisFormat, thisShape);
  2894.     anErr = GXGetJobError(pData->hPrint);
  2895.     nrequire(anErr, PrintPage);
  2896.  
  2897.     GXDisposeFormat(thisFormat);
  2898.     GXDisposeShape(thisShape);
  2899.  
  2900. // FALL THROUGH EXCEPTION HANDLING
  2901. PrintPage:
  2902. ReadPrintFilePage:
  2903.     // tell it to stop printing when we reach the end
  2904.     if (*pageNum >= ((GXDataPtr)pData)->numberOfPages)
  2905.         *pageNum = -1;
  2906.     
  2907.     return(anErr);
  2908.     
  2909. } // GXFilePrintPage
  2910.  
  2911. // --------------------------------------------------------------------------------------------------------------
  2912.  
  2913. OSErr    GXGetDocumentRect(WindowRef pWindow, WindowDataPtr pData, 
  2914.             LongRect * documentRectangle, Boolean forGrow)
  2915. {
  2916. #pragma unused (pWindow, forGrow)
  2917.  
  2918.     gxRectangle        pageSize, paperSize;
  2919.     
  2920.     GetCurrentPageAndPaper(pData, &pageSize, &paperSize);
  2921.  
  2922.     documentRectangle->left = 0;
  2923.     documentRectangle->top = 0;
  2924.     documentRectangle->bottom = FixedMultiply(paperSize.bottom - paperSize.top, ((GXDataPtr)pData)->zoomFactor) >> 16;
  2925.     documentRectangle->right = FixedMultiply(paperSize.right - paperSize.left, ((GXDataPtr)pData)->zoomFactor) >> 16;
  2926.         
  2927.     return(noErr);
  2928.     
  2929. } // GXGetDocumentRect
  2930.  
  2931. // --------------------------------------------------------------------------------------------------------------
  2932.  
  2933. static long GXCalculateIdleTime(WindowRef pWindow, WindowDataPtr pData)
  2934. {
  2935. #pragma unused (pWindow)
  2936.  
  2937.     if (!EmptyRect( &((GXDataPtr)pData)->selectionRectangle))
  2938.         return(0);
  2939.     else
  2940.         return(kMaxWaitTime);
  2941.         
  2942. } // GXCalculateIdleTime
  2943.  
  2944. // --------------------------------------------------------------------------------------------------------------
  2945.  
  2946. static Boolean    GXFilterEvent(WindowRef pWindow, WindowDataPtr pData, EventRecord *pEvent)
  2947. {
  2948.     if     (
  2949.         (!gMachineInfo.amInBackground) &&
  2950.         (pEvent->what == nullEvent) &&
  2951.         (pWindow == FrontWindow()) &&
  2952.         (EmptyRgn( ((WindowPeek)pWindow)->updateRgn)) &&
  2953.         (MOVESELECTION(pEvent->when) )
  2954.         )
  2955.         {
  2956.         // erase the old
  2957.         DrawSelection(pData, &((GXDataPtr)pData)->selectionRectangle, &((GXDataPtr)pData)->patternPhase, false);
  2958.         
  2959.         // draw the new, moving onto the next pattern
  2960.         DrawSelection(pData, &((GXDataPtr)pData)->selectionRectangle, &((GXDataPtr)pData)->patternPhase, true);
  2961.         }
  2962.         
  2963.     return(false);
  2964.     
  2965. } // GXFilterEvent
  2966.  
  2967. // --------------------------------------------------------------------------------------------------------------
  2968.  
  2969. static OSErr    GXDragAddFlavors(WindowRef pWindow, WindowDataPtr pData, DragReference theDragRef)
  2970. {
  2971. #pragma unused (pWindow)
  2972.  
  2973.     OSErr    anErr = noErr;
  2974.     
  2975.     SetDragSendProc(theDragRef, gGXSendDataProc, nil);
  2976.     AddDragItemFlavor(theDragRef, (unsigned long)pData, 'qdgx', nil, 0, 0);
  2977.     AddDragItemFlavor(theDragRef, (unsigned long)pData, 'PICT', nil, 0, 0);
  2978.     
  2979.     return(anErr);
  2980.     
  2981. } // GXDragAddFlavors
  2982.  
  2983. // --------------------------------------------------------------------------------------------------------------
  2984.  
  2985. static OSErr    GXAdjustCursor(WindowRef pWindow, WindowDataPtr pData, Point * localMouse, Rect * globalRect)
  2986. {
  2987. #pragma unused (pWindow, globalRect)
  2988.  
  2989.     OSErr            anErr = noErr;
  2990.     Handle        theCursor;
  2991.     Rect            selectionRect = ((GXDataPtr)pData)->selectionRectangle;
  2992.     
  2993.     OffsetRect(&selectionRect, -GetControlValue(pData->hScroll), -GetControlValue(pData->vScroll));
  2994.     if (!PtInRect(*localMouse, &selectionRect) )
  2995.         {
  2996.         short    cursorID;
  2997.         Boolean    colorCursor;
  2998.         
  2999.         cursorID = ((GXDataPtr)pData)->contentClickMode;
  3000.         if (cursorID == kSelectionTool)
  3001.             {
  3002.             colorCursor = false;
  3003.             cursorID = crossCursor;
  3004.             }
  3005.         else
  3006.             {
  3007.             colorCursor = true;
  3008.             cursorID += kIconBase;
  3009.             }
  3010.             
  3011.         if (colorCursor)
  3012.             theCursor = (Handle)GetCCursor(cursorID);
  3013.         else
  3014.             theCursor = (Handle)GetCursor(cursorID);
  3015.         if (theCursor)
  3016.             {
  3017.             if (colorCursor)
  3018.                 {
  3019.                 SetCCursor((CCrsrHandle)theCursor);
  3020.                 DisposeCCursor((CCrsrHandle)theCursor);
  3021.                 }
  3022.             else
  3023.                 {
  3024.                 char    oldState;
  3025.                 
  3026.                 oldState = HGetState(theCursor);
  3027.                 HLock((Handle) theCursor);
  3028.                 SetCursor(*(CursHandle)theCursor);
  3029.                 HSetState(theCursor, oldState);
  3030.                 }
  3031.             anErr = eActionAlreadyHandled;
  3032.             }
  3033.         }
  3034.     return(anErr);
  3035.     
  3036. } // GXAdjustCursor
  3037.  
  3038. // --------------------------------------------------------------------------------------------------------------
  3039.  
  3040. static OSErr    GXMakeWindow(WindowRef pWindow, WindowDataPtr pData)
  3041. {
  3042.     OSErr                anErr = noErr;
  3043.     
  3044.     pData->pCloseWindow         = (CloseWindowProc)            GXCloseWindow;
  3045.     pData->pAdjustMenus         = (AdjustMenusProc)            GXAdjustMenus;
  3046.     pData->pCommand                = (CommandProc)                GXCommand;
  3047.     pData->pUpdateWindow         = (UpdateWindowProc)        GXUpdateWindow;
  3048.     pData->pContentClick         = (ContentClickProc)        GXContentClick;
  3049.     pData->pGetDocumentRect     = (GetDocumentRectProc)        GXGetDocumentRect;
  3050.     pData->pPrintPage             = (PrintPageProc)            GXFilePrintPage;
  3051.     pData->pFilterEvent             = (FilterEventProc)            GXFilterEvent;
  3052.     pData->pCalculateIdleTime    = (CalculateIdleTimeProc)    GXCalculateIdleTime;
  3053.     pData->pAdjustCursor        = (AdjustCursorProc)        GXAdjustCursor;
  3054.     pData->pDragAddFlavors        = (DragAddFlavorsProc)        GXDragAddFlavors;
  3055.     
  3056.     pData->documentOutputsGX    = true;
  3057.     pData->hasGrow                = true;
  3058.     pData->minHSize                = kMinGXDocSize + kScrollAreaWidth + kZoomControlsWidth + kToolControlWidth;
  3059.     pData->hScrollAmount        = 10;
  3060.     pData->vScrollAmount        = 10;
  3061.     pData->hScrollOffset        = kScrollAreaWidth + kZoomControlsWidth + kToolControlWidth;
  3062.     
  3063.     // default the job info, which we need to have
  3064.     anErr = DoDefault(pData);
  3065.     nrequire(anErr, DoDefault);
  3066.  
  3067.     ((GXDataPtr)pData)->thePrintFile = GXOpenPrintFile(pData->hPrint, &pData->fileSpec, fsRdWrPerm);
  3068.     anErr = GXGetJobError(pData->hPrint);
  3069.     nrequire(anErr, OpenPrintFile);
  3070.  
  3071.     /*
  3072.      *    The assumption here is that the GXOpenPrintFile leaves the resfile on top.
  3073.      *    We need this refnum so that any resource handles the translator gets will
  3074.      *    match those that GXOpenPrintFile used for calls to GXNewFont.  See the call
  3075.      *    to GXDrawShape in GXUpdateWindow
  3076.      */
  3077.     ((GXDataPtr)pData)->printFileRefNum = CurResFile();
  3078.  
  3079.     // close down other paths to the file -- because we don't need them
  3080.     if (pData->resRefNum != -1)
  3081.         {
  3082.         CloseResFile(pData->resRefNum);
  3083.         pData->resRefNum = -1;
  3084.         }
  3085.     if (pData->dataRefNum != -1)
  3086.         {
  3087.         FSClose(pData->dataRefNum);
  3088.         pData->dataRefNum = -1;
  3089.         }
  3090.         
  3091.     // default to normal printing -- so if the user prints, we go to normal mode at first
  3092.     {
  3093.     Collection    jobCollection = GXGetJobCollection(pData->hPrint);
  3094.     gxJobInfo    theInfo;
  3095.     long        theSize = sizeof(theInfo);
  3096.     
  3097.     if (GetCollectionItem(jobCollection, gxJobTag, gxPrintingTagID, &theSize, &theInfo) == noErr)
  3098.         {
  3099.         theInfo.priority = gxPrintJobASAP;
  3100.         AddCollectionItem(jobCollection, gxJobTag, gxPrintingTagID, theSize, &theInfo);
  3101.         }
  3102.     
  3103.     }
  3104.     
  3105.     // by default we have no pages
  3106.     ((GXDataPtr)pData)->numberOfPages        = GXCountPrintFilePages(((GXDataPtr)pData)->thePrintFile);
  3107.     ((GXDataPtr)pData)->currentPage            = 1;
  3108.     ((GXDataPtr)pData)->zoomFactor            = ff(1);
  3109.     ((GXDataPtr)pData)->contentClickMode    = kSelectionTool;
  3110.     anErr = GXGetJobError(pData->hPrint);
  3111.     if ( (anErr == noErr) && (((GXDataPtr)pData)->numberOfPages == 0) )
  3112.         anErr = eDocumentContainsNoPages;
  3113.     nrequire(anErr, GXCountPrintFilePages);
  3114.     
  3115.     if (((GXDataPtr)pData)->numberOfPages > 1)
  3116.         pData->hScrollOffset += kPageControlsWidth;
  3117.         
  3118.     ((GXDataPtr)pData)->pageAnnotations = (gxShape**) NewHandleClear( (((GXDataPtr)pData)->numberOfPages * sizeof(gxShape)) );
  3119.     anErr = MemError();
  3120.     if (anErr == noErr)
  3121.         anErr = LoadOrSaveAnnotations(pData, kLoadAnnotations);
  3122.     nrequire(anErr, FailedToAllocateAnnotation);
  3123.     
  3124.     // set up so we can draw inside of this window
  3125.     ((GXDataPtr)pData)->parentViewPort = GXNewWindowViewPort((WindowPtr)pWindow);
  3126.     ((GXDataPtr)pData)->childViewPort = GXNewViewPort(gxScreenViewDevices);
  3127.     GXSetViewPortParent(((GXDataPtr)pData)->childViewPort, ((GXDataPtr)pData)->parentViewPort);
  3128.     GXSetViewPortAttributes(((GXDataPtr)pData)->childViewPort, gxAlwaysGridPort);
  3129.     GXSetViewPortDither(((GXDataPtr)pData)->childViewPort, 4);
  3130.     
  3131.     // fetch the current page
  3132.     anErr = GetCurrentPage((GXDataPtr) pData, true);
  3133.     nrequire(anErr, GetCurrentPage);
  3134.     
  3135.     // if this document contains PostScript do a warning
  3136.     {
  3137.     gxTranslatedDocumentInfo theInfo;
  3138.     long theSize = sizeof(theInfo);
  3139.     
  3140.     if     (
  3141.         (GetCollectionItem(GXGetJobCollection(pData->hPrint),
  3142.                             gxTranslatedDocumentTag,
  3143.                             gxPrintingTagID,
  3144.                             &theSize,
  3145.                             &theInfo
  3146.                             ) == noErr) &&
  3147.         (theInfo.translatorInfo & gxContainsPostScript)
  3148.         )
  3149.         ConductErrorDialog(eDocumentContainsPS, cOpen, ok);
  3150.     }
  3151.     
  3152.     return(anErr);
  3153.     
  3154. // EXCEPTION HANDLING
  3155. GetCurrentPage:
  3156. FailedToAllocateAnnotation:
  3157. GXCountPrintFilePages:
  3158.     GXClosePrintFile( ((GXDataPtr)pData)->thePrintFile);
  3159.     
  3160. OpenPrintFile:
  3161.     GXDisposeJob(pData->hPrint);
  3162.         
  3163. DoDefault:
  3164.     return(anErr);
  3165.     
  3166. } // GXMakeWindow
  3167.  
  3168.  
  3169. // --------------------------------------------------------------------------------------------------------------
  3170.  
  3171. OSErr    GXPreflightWindow(PreflightPtr pPreflightData)
  3172. {    
  3173.     pPreflightData->continueWithOpen     = true;
  3174.     pPreflightData->wantVScroll            = true;
  3175.     pPreflightData->wantHScroll            = true;
  3176.     pPreflightData->doZoom                = true;
  3177.     pPreflightData->makeProcPtr         = GXMakeWindow;
  3178.     pPreflightData->storageSize         = sizeof(GXDataRecord);
  3179.     
  3180.     return(noErr);
  3181.     
  3182. } // GXPreflightWindow
  3183.  
  3184. // --------------------------------------------------------------------------------------------------------------
  3185.  
  3186. void GXGetFileTypes(OSType * pFileTypes, OSType * pDocumentTypes, short * numTypes)
  3187. {
  3188.     if (gMachineInfo.haveGX)
  3189.         {
  3190.         pFileTypes[*numTypes]         = 'sjob';
  3191.         pDocumentTypes[*numTypes]     = kGXWindow;
  3192.         (*numTypes)++;
  3193.  
  3194.         pFileTypes[*numTypes]         = 'tjob';
  3195.         pDocumentTypes[*numTypes]     = kGXWindow;
  3196.         (*numTypes)++;
  3197.  
  3198.         pFileTypes[*numTypes]         = 'rjob';
  3199.         pDocumentTypes[*numTypes]     = kGXWindow;
  3200.         (*numTypes)++;
  3201.  
  3202.         pFileTypes[*numTypes]         = 'qjob';
  3203.         pDocumentTypes[*numTypes]     = kGXWindow;
  3204.         (*numTypes)++;
  3205.         }
  3206.         
  3207. } // GXGetFileTypes
  3208.